Manejo de infomación con WebSockets¶
Sails usa socket.io como el motor subyacente para la comunicación, por lo que la especificación de la comunicación se ejemplifica con fragmentos de código JavaScript.
El sistema debe notificar a los asistentes y a los temporizadores de las estaciones cuando se lleven a cabo acciones de los usuarios que requieran atención. Esta comunicación será llevada a cabo utilizando la tecnología WebSocket.
Descripción general¶
Establecimiento de conexión¶
- El cliente intenta establecer una conexión con el servidor Onsite
en la ruta
{local_ip}:1337/notifications, donde local_ip corresponde a la IP local del servidor Onsite; y notifications es el nombre del espacio de nombres que se usará para el manejo de conexiones WebSocket. - El servidor recibe la conexión y crea un socket para comunicarse con el cliente.
- Inmediatamente después de establecer la conexión, el cliente debe autenticarse ante Onsite como el tipo de cliente que anunció.
- El servidor responde con el resultado de la autenticación. Si el proceso es exitoso, el servidor incluirá al cliente en el room correspondiente. Si la autenticación resulta en error, el servidor cierra el socket.
Flujo¶
La conexión entre el cliente y el servidor se establece sin autenticación. Por lo tanto, inmediatamente después de establecer conexión, el cliente debe identificarse ante Onsite con una petición firmada con un JWT de la siguiente manera:
Servidor¶
connect: function (req, res) {
var socket = req.socket;
var jwtAuth = req.body.params['jwt-api-key'];
// JWT validation goes here
}
Cliente¶
Conexión hacia Onsite
var notifications = io.connect('https://[local].onsite.gamersarena.com.mx/');
notifications.emit('get', {
url: "/notifications",
params: {
"jwt-api-key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
}
}, function(data) {
// data is server response
});
Conexión hacia Tournament Handler
var notifications = io.connect('http://tournament.gamersarena.com.mx/');
notifications.emit('get', {
url: "/notifications",
params: {
"jwt-api-key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ",
"tournamentId": 2 // identificador del torneo para recibir notificaciones
}
}, function(data) {
// data is server response
});
Si el proceso de autenticación es exitoso, el servidor debe
agregar al cliente al room correspondiente dependiendo de la
entidad a la que pertenezca su JWT. Adicionalmente, se establece
en la BD el identificador del socket asociado al cliente, el
cual se obtiene invocando a la variable id del socket.
Si la autenticación falla, el servidor cierra el socket asociado
al cliente cuyas credenciales no pudieron ser verificadas. Esto
se logra invocando a la función disconnect() del socket.
Enlace a room¶
Un room es un conjunto de sockets identificados por un nombre, el cual es usado para enviar mensajes a un subconjunto de los clientes conectados.
Por defecto, cada socket se une automáticamente a un room cuyo nombre es el id del socket. Con el objetivo de propagar mensajes a cierto tipo de clientes en el local, es conveniente incorporarlos a un room dependiendo de su rol.
Los rooms gestionados por el sistema Onsite son:
- assistant
- timer
Por otro lado, en Tournament Handler se crean rooms con la estructura:
assistant_[id], dondeidcorresponde al identificador del- torneo en Tournament Handler al cual está suscrito el asistente.
Agregar a un cliente a un room se logra de la siguiente manera
socket.join('room name');
Y después enviar un mensaje a los sockets en el room como sigue
broadcast('room name', "eventName", message_as_object);
donde
- room names es el nombre o nombres (arreglo de cadenas) de los rooms a los cuales enviar el mensaje
- eventName es el identificador de la operación
- message_as_object es el objeto que se envía como mensaje
Desconexión¶
En caso de ocurrir un desconexión de parte de el cliente, su
id de socket debe ser limpiado de la base de datos, lo cual
se logra estableciendo como nulo el campo socket_id de la
entidad correspondiente.
Estuctura de los mensajes¶
Servidor¶
Si la comunicación es iniciada por el servidor, los mensajes enviados tienen una estructura de objeto como la siguiente:
{
check_in_id: {
id: 4,
nick: "aguila_calva"
}
}
donde el cuerpo es variable, por lo que la estructura del mensaje esperado por el cliente será descrita en la especificación de cada evento.
Si el mensaje corresponde a una respuesta de una petición efectuada por el cliente, la estructura será la siguiente:
{
body: {
error: {
code: '409-13',
message: 'There was a problem with the checkin.'
}
},
statusCode: 409
}
Si la respuesta fue exitosa, el campo error no es incluido.
Cliente¶
Los mensajes del cliente siempre presentan dos campos: header y body. En el header se incluyen encabezados de la operación, como el token de autenticación. Por otro lado, el body alberga los valores relativos a la transacción.
{
"header": {
"jwt-api-key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
},
"body": {
"check_in_id": {
"id": 4,
"nick": "aguila_calva"
}
}
}