Connexions WebSocket

Les canaux WebSocket créés dans Dashboard sont indépendants du langage de programmation, ce qui signifie qu'ils peuvent être utilisés pour invoquer des services et publier ou recevoir des messages à partir de toute application parlant WebSockets et JSON, par exemple Python, JavaScript ou autre.

Pour utiliser les canaux WebSocket, les applications (clients API) doivent suivre un protocole décrit dans ce chapitre.

  • Après l'ouverture d'un flux TCP initial, le client doit obtenir un token dans un certain délai (par défaut, 5 secondes).
  • Le token renvoyé par Zato identifie de manière unique cette connexion client particulière jusqu'à son socket TCP.
  • Le token est une chaîne aléatoire considérée comme un secret et ne doit pas être partagé avec un autre client ou une autre connexion.
  • Aucun autre client n'est autorisé à réutiliser un token déjà émis et chaque connexion ne possède qu'un seul token tout au long de son existence.
  • Bien que le token soit une chaîne aléatoire forte, il ne peut être utilisé que pour l'identification du client et ne doit pas être utilisé côté client à des fins cryptographiques (il existe des API crypto dédiées dans Zato pour de tels besoins).
  • Chaque token a un TTL, un Time To Live, qui est par défaut de 864000 secondes = 10 jours. Chaque fois que le canal est invoqué, le TTL du token est prolongé d'autant de secondes par rapport à l'heure actuelle. Si le token atteint son TTL, toute invocation ultérieure sera rejetée et le socket TCP sera fermé.
  • Les clients doivent envoyer des trames Ping WebSocket (conformément à RFC-6455) au moins une fois toutes les 30 secondes. Si 5 pings consécutifs d'un client sont manqués, la connexion est interrompue par Zato.
  • Les trames de ping ne doivent pas envoyer de données commerciales, elles servent uniquement à maintenir les connexions en vie.
  • Les applications peuvent aussi bien invoquer des services d'API que prendre part à des flux de travail de publish/subscribe - dans ce dernier cas, elles peuvent agir en tant qu'éditeurs, abonnés ou les deux.

Connexion et obtention d'un token de session

Les clients établissent une connexion WebSocket initiale à l'adresse utilisée par un canal donné, en tenant compte éventuellement du fait qu'un équilibreur de charge peut effectuer des transformations d'URL ou des mappages de ports devant les serveurs Zato.

Une fois la connexion établie, les clients doivent créer une session et recevoir un token de session. Cette étape doit être effectuée même si, pour un canal WebSocket donné, aucune information d'identification du client n'est nécessaire.

Les clients doivent utiliser le token de session dans toutes les demandes effectuées sur la même connexion TCP. Le token ne peut pas être utilisé pour d'autres connexions, il est spécifique à un flux TCP.

Juste après l'établissement d'une connexion TCP, avant de se connecter, une entrée d'information est stockée dans les logs du serveur. Elle comprend des données sur l'adresse IP et le nom de domaine d'où provient la connexion, ainsi que l'adresse et le nom du canal WebSocket.

INFO - New connection from 127.0.0.1:51738 (localhost) to 127.0.0.1:48902 (my.wsx.channel)

Si un client se connecte mais ne lance pas la demande de création de session dans le délai prévu, la connexion TCP sera fermée avec un message d'avertissement dans les logs du serveur:

WARNING - Peer 127.0.0.1:51738 (localhost) did not create session within 5s,
closing its connection to 127.0.0.1:48902 (my.wsx.channel), cid:`23b3cae088382f62106edd67`

Sinon, si le client crée une session avec succès, un message informatif sera enregistré dans les logs:

INFO - Client 127.0.0.1:57288 (localhost ws.eee4b49d6fd835b424175ed5)
logged in successfully to 127.0.0.1:48902 (my.wsx.channel)

Requête

Élément Type de données Optionnel Notes
meta dict --- Un dictionnaire de métadonnées pour la requête
meta.action string --- Une valeur constante de "create-session".
meta.username string Yes Nom d'utilisateur pour l'authentification (si nécessaire)
meta.secret string Yes Mot de passe ou autre secret spécifique au canal pour s'authentifier (si nécessaire)
meta.id string --- ID de la demande généré par le client - doit être unique au monde (par exemple, UUID4). Renvoyé dans les réponses dans l'élément in_reply_to pour permettre aux clients de savoir en réponse à quelle demande une réponse donnée est renvoyée.
meta.timestamp datetime --- Date à laquelle le message a été généré par le client, doit être en UTC en utilisant l'ISO-8601 YYYY-MM-DDTHH:mm:ss.ssssss
meta.client_id string --- Un identifiant professionnel arbitraire du client - toute valeur identifiant le client peut être utilisée, par exemple l'identifiant d'une application professionnelle comme crm.prod.1 ou l'identifiant d'un appareil IoT se connectant à Zato comme printer.mx2.3910.
meta.client_name string Yes Identifiant convivial du client (en plus de client_id)
{"meta": {
  "action": "create-session",
  "username": "user1",
  "secret": "PNVmGkLejnhsAZ5VzzfdHQkvGg",
  "id": "238dc406351444d0869390af9541da59",
  "timestamp": "2022-11-16T15:53:25.717215",
  "client_id": "p.33915",
  "client_name": "Printer #33915, Fifth floor"
  }}

Réponse

Élément Type de données Optionnel Notes
meta dict --- Un dictionnaire de métadonnées pour la réponse
meta.status integer --- Un code d'état global, utilisant le code d'état HTTP, par exemple 200 est OK.
meta.timestamp datetime --- Quand la réponse a été produite par Zato, en UTC
id string --- Response ID - son dernier élément est un ID de corrélation qui peut être utilisé pour rechercher des détails dans le log du serveur.
in_reply_to string Yes En réponse à quelle demande ID la réponse est retournée
data any --- Business data liées à la réponse. En cas d'erreur, il s'agira d'un message d'erreur. Sinon, il contiendra un élément avec le token de session.
data.token string Yes Un token de session généré aléatoirement - renvoyé uniquement si le statut méta est 200

Échantillons:

{"meta":{
  "status":200,
  "timestamp":"2022-04-11T09:17:16.954645",
  "in_reply_to":"238dc406351444d0869390af9541da59",
  "id":"zato.ws.srv.rsp-auth.39d6e397054e410810afeac2"},
"data":{
  "token":"ws.token.b76561f8c145cd6baf086d04"}}
{"meta": {
  "status":403,
  "timestamp":"2022-04-11T09:02:20.918796",
  "id":"zato.ws.srv.msg-err.82608509fb56261fd8c90910"},
  "data":"You are not authorized to access this resource"}

Invoquer des services

Les clients possédant un token de session peuvent invoquer le service qui est monté sur un canal WebSocket auquel ils sont connectés.

Cela signifie que si un client veut invoquer plusieurs services, le service du canal doit transmettre les messages aux services réels en utilisant self.invoke et renvoyer la réponse au client appelant en l'assignant à self.response.payload. Cela permet d'implémenter des listes blanches où seuls les services sélectionnés peuvent être rendus accessibles à l'appelant et où les tentatives d'invoquer tout autre service seront rejetées.

Il existe également un service de passerelle WebSockets par défaut qui peut être utilisé pour invoquer n'importe quel service, il est documenté dans le chapitre ci-dessous.

Requête

Élément Type de données Optionnel Notes
meta dict --- Un dictionnaire de métadonnées pour la requête
meta.action string --- Une valeur constante de "invoke-service".
meta.id string --- Comme dans l'action "create-session".
meta.timestamp datetime ---
meta.token string --- token de session renvoyé par l'action "create-session".
data any --- Données arbitraires requises par le service du canal - peut être une chaîne, un entier, un dict ou n'importe quoi d'autre que le service attend.

Cet exemple suppose que le service zato.helpers.echo est monté sur le canal - c'est un service intégré qui renvoie en écho tout ce qu'il reçoit en entrée.

{"meta": {
  "action": "invoke-service",
  "id": "36df91fca2444dcaadc7199691217cfd",
  "timestamp": "2016-11-16T15:53:25.717215",
  "token": "ws.token.7a1729f99acbfe21b0cca337"},
  "data": {
    "customer_id": "123",
    "account_id": "456"
  }}

Response

Élément Type de données Optionnel Notes
meta dict --- Comme dans l'action "create-session".
meta.status integer ---
meta.timestamp datetime ---
id string ---
in_reply_to string Yes
data any --- Business data liées à la réponse. En cas d'erreur, il s'agira d'un message d'erreur. Sinon, il contiendra la réponse que le service du canal a renvoyée - il peut s'agir d'une chaîne de caractères, d'un nombre entier, d'un dictionnaire ou de tout autre type de données.

Une fois encore, l'exemple montre ce que zato.helpers.echo peut renvoyer s'il est affecté à un canal WebSocket.

{"meta":{
  "status":200,
  "timestamp":"2022-04-11T11:38:34.400736",
  "in_reply_to":"36df91fca2444dcaadc7199691217cfd",
  "id":"zato.ws.srv.rsp-ok.05308f81590751038cc9167f"},
  "data":{
    "customer_id":"123",
    "account_id":"456"
  }}

Fermeture des sessions et déconnexion

Il n'existe pas d'appel d'API distinct pour fermer une session et se déconnecter. Il suffit de fermer la connexion WebSocket ainsi que son flux TCP - ceci sera immédiatement reconnu par Zato et toutes les actions de fermeture et de nettoyage pertinentes seront effectuées.

Ensuite, le token de session ne peut plus être utilisé, même par le même client ; une nouvelle session doit être créée avec son propre token.

Utilisation de la passerelle WebSockets par défaut

Un service intégré appelé helpers.web-sockets-gateway peut être monté sur un canal WebSocket pour permettre aux clients d'invoquer tout autre service arbitraire.

Notez cependant que les clients auront réellement accès à tout service déployé sur le serveur auquel ils se connecteront, y compris tous les services internes. Si cela n'est pas souhaitable, le service de passerelle peut être sous-classé pour mettre en œuvre une logique de liste blanche, c'est-à-dire pour filtrer les demandes qui tentent d'invoquer un service en dehors de la liste des services autorisés.