Symfony

Faire une application temps-réel: à la découverte de Mercure

En début de semaine, j’ai dû étudier la réalisation d’un widget de live scoring. Le but était d’afficher sur un site internet les résultats d’un match, mis à jour en temps réel. Cela était l’occasion de sortir un petit peu de Symfony et PHP pour découvrir d’autres technologies, en l’occurence Mercure dont j’avais beaucoup entendu parler depuis la SymfonyLive Lille.

Mercure, késako?

Derrière le nom de Mercure se cachent à la fois un protocole, spécifié exhaustivement (ici) et ouvert, et une implémentation serveur (en Go, ici sur Github).
Le principe de base est le suivant: un publisher envoie un message, via une requête POST, au serveur. Le serveur va diffuser ce message à tous les clients connectés. Il s’agit d’une communication uni-directionnelle.
De plus, il y a une notion de topic, de sujet, ainsi un seul serveur peut supporter plusieurs « conversations » simultanées.

Techniquement, la connexion des clients et la diffusion des messages est rendue possible grâce à HTTP/2 et Server-Sent Events. Cette technologie est supportée par tous les navigateurs récents, y compris Microsoft Edge et Safari Mobile, ainsi que par un certain nombre de librairies pour des applications natives (iOS, Mac…).
Une authentification par JSON Web Token permet de limiter qui peut publier. Optionnellement, on peut aussi requérir une authentification pour les clients, pour la lecture. Le protocole étant basé sur HTTP, il est possible de plus de les chiffrer avec HTTPS, simplement.

Un exemple

Mercure a de très nombreux cas d’utilisation, on peut imaginer développer ainsi des applications se mettant à jour en temps réel (à la manière d’un push), web ou mobiles, un client de chat, des outils collaboratifs…
Pour mon exemple, je vais rester sur le cas du widget de site internet affichant des scores en temps réel. Nous allons donc réaliser une petite page internet, client.html, et pour le publisher, nous allons le simuler avec un simple fichier PHP, publisher.php. Tout va tourner en local, sans chiffrement.

Petite étape préliminaire, pour l’authentification, nous devons choisir une clef privée, et générer un JWT. Je choisis ici clef-privee-2-romaric-net1nf, et je génère le token grâce au debugger de jwt.io.

Pour le serveur, j’ai choisi d’utiliser l’image Docker pour simplifier.
Dans l’ordre des arguments, on doit passer notre clef privée ; on se met en mode démo ; tout le monde peut écouter et lire les messages ; les CORS doivent être relâchés au maximum (*) car on est sur localhost ; et on configure sur l’écoute sur le port 80.
La ligne de commande à exécuter:

docker run \
   -e JWT_KEY='clef-privee-2-romaric-net1nf' -e DEMO=1 -e ALLOW_ANONYMOUS=1 -e CORS_ALLOWED_ORIGINS='*' -e PUBLISH_ALLOWED_ORIGINS='http://localhost' \
   -p 80:80 \
   dunglas/mercure

On peut ensuite ouvrir client.html dans notre navigateur. Pas besoin de l’afficher à travers un serveur web, ouvrir directement le fichier fonctionne (avec Chrome, au moins).
On envoie un message en exécutant le script PHP, php -f publisher.php. On peut optionnellement passer un autre nom, par exemple: php -f publisher.php Fabien.

Voici le résultat, avec en arrière-plan la page web, au milieu le retour de l’exécution du script PHP, et en bas les logs du serveur:

Le code complet est sur Gist:

Bilan

J’espère que cet exemple basique vous aura fait découvrir la technologie et vous donnera envie de l’essayer. Si vous souhaitez envoyer des messages depuis une application Symfony, il existe un bundle officiel pour l’intégrer, notamment au niveau de la configuration. Convaincus? 🙂

Visited 187 times, 1 visit(s) today