![Page 1: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/1.jpg)
Phoenix Presence: Le service tempsréel de Phoenix 1.2Mickaël RémondProcessOne
![Page 2: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/2.jpg)
Brève histoire de Phoenix
![Page 3: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/3.jpg)
Qu'est-ce que Phoenix ?
Framework de développement Web
Développement lancé en août 2014 avec un focus sur les websockets
Inspiration venant de différents frameworks: Ruby on Rails, Clojure Ring, ScalaPlayframework, ...
Version 1.0 sortie en août 2015.
Version 1.1 en décembre 2015.
Version 1.2 majeure en juin 2016.
![Page 4: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/4.jpg)
Les atouts de Phoenix
Points forts:
Élégance grâce à la syntaxe d'Elixir et à son système de macros (DSL)
Performance et clustering grâce à la VM Erlang
Productivité avec des outils de base de données comme Ecto
Fonctionnalités:
couvre le support des pages web dynamiques.
interactions temps réel: websockets et presence.
![Page 5: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/5.jpg)
De Phoenix 1.0 à Phoenix 1.2
Phoenix 1.1:
Amélioration des performances des channels
Localisation via Gettext
Phoenix 1.2:
Ecto 2.0
Phoenix Presence
![Page 6: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/6.jpg)
Références
Introduction au développement Web avec le framework Phoenix
www.youtube.com/watch?v=GPF6w3CsWio (https://www.youtube.com/watch?v=GPF6w3CsWio)
Site Web de Phoenix
www.phoenixframework.org (http://www.phoenixframework.org)
![Page 7: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/7.jpg)
Websockets, Channels, Presence: Les concepts
![Page 8: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/8.jpg)
Définitions
Websockets: protocole de communication entre le navigateur et le serveur. Maintiens laconnexion pendant la durée de la session.
Channels: Les channels définisset le comportement du serveur pour le broadcast demessage en temps réel, par "sujet" (topic).
Presence: Le module de "présence tracker synchronize l'état des joins et des leaves desur les topics, via le module channel, et broadcast les changements.
![Page 9: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/9.jpg)
Architecture
![Page 10: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/10.jpg)
Presence vs Channels ?
La fonctionnalité de Phoenix Presence vient sous la forme d'un presence tracker.
Il s'agit d'une structure de données en mémoire, répliquée et synchronisée en temps réel sur tous les noeuds d'un cluster Elixir.
Elle s'appuie sur les channels:
pour recevoir les événements de join et de leave.
pour envoyer l'état initial et les mises à jour incrémentales.
Phoenix Presence permet:
la découverte de service / composants du système.
la gestion de la présence des utilisateurs.
![Page 11: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/11.jpg)
Points forts de Phoenix Presence
Robustesse:
Réplication en temps réel sur l'ensemble du cluster.
pas de point de failure unique (SPOF).
peut continuer à fonctionner lors d'un netsplit.
supporte de fortes charges.
Simplicité:
de gestion: gère la réconciliation automatiquement lorsque le cluster se reconstitue.
de déploiement: dépends uniquement de module standard, sans dépendance externe.
d'implémentation: est fourni avec un module Javascript pour faciliter l'implémentationdes clients.
![Page 12: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/12.jpg)
Limitations
Phoenix Presence est une structure de données distribuée. Les fonctionnalités restentd'assez bas niveau.
Il est idéal pour gérer la présence en temps réel pour des communautés:
Site web
Jeu vidéo
Il reste un système simple, fonctionnant sur la base de topic et de channels:
Pas de liste de contacts / présence individuelle.
![Page 13: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/13.jpg)
Mise en œuvre
![Page 14: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/14.jpg)
L'exemple Gastronokids
Application d'illustration utilisée dans ma précédente présentation sur Phoenix.
github.com/ElixirParis/gastronokids (https://github.com/ElixirParis/gastronokids)
Enrichissement pour ajouter un module de présence.
![Page 15: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/15.jpg)
Étape 1: Mise à jour de Phoenix 1.0 à Phoenix 1.2
![Page 16: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/16.jpg)
Changements
Résumé:
Migration vers Postgres: SQLite Ecto ne fonctionne pas encore avec Ecto 2.0
Mise à jour des dépendances Elixir et Javascript
Mise à jour vers Ecto 2.0: Model -> Schema
Ajout du support de la localisation Gettext
Changement du code de gestion des erreurs dans les formulaires
Commit complet:
Github: Migrate for Phoenix 1.0 to Phoenix 1.2 + move to Postgres(https://github.com/ElixirParis/gastronokids/commit/418e10926c7e647b47628d2006a91123496a57da)
![Page 17: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/17.jpg)
Étape 2: Ajout du module de présence
![Page 18: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/18.jpg)
Générer le code du module Presence
Utilisation du scaffolding pour générer le code:
$ mix phoenix.gen.presence * creating web/channels/presence.ex Add your new module to your supervision tree, in lib/gastronokids.ex: children = [ ... supervisor(Gastronokids.Presence, []), ] You're all set! See the Phoenix.Presence docs for more details: http://hexdocs.pm/phoenix/Phoenix.Presence.html
Nous utilisons le module en l'état.
![Page 19: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/19.jpg)
Configuration
![Page 20: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/20.jpg)
Ajouter le service de présence dans l'application
Dans lib/gastronokids.ex, ajout du module dans l'arbre de supervision:
def start(_type, _args) do import Supervisor.Spec, warn: false children = [ # Start the endpoint when the application starts supervisor(Gastronokids.Endpoint, []), # Start the Ecto repository worker(Gastronokids.Repo, []), # Presence tracker: supervisor(Gastronokids.Presence, []), ] # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: Gastronokids.Supervisor] Supervisor.start_link(children, opts) end
![Page 21: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/21.jpg)
Config PubSub
Vérifier que le service PubSub est bien configuré dans config/config.exs:
config :gastronokids, Gastronokids.Endpoint, url: [host: "localhost"], secret_key_base: "j458rtSt4qQnUmBDEVmjX3X6tCtLLjWJy6rhO58WO86s1S2I3i4zePgdcV/T3N41", render_errors: [view: Gastronokids.ErrorView, accepts: ~w(html json)], # This is mapping between name and pubsub backend pubsub: [name: Gastronokids.PubSub, adapter: Phoenix.PubSub.PG2]
![Page 22: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/22.jpg)
room_channel.ex
![Page 23: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/23.jpg)
Lier la présence aux channels (1/2)
Importer notre module de présence dans web/channel/room_channel.ex:
defmodule Gastronokids.RoomChannel do use Gastronokids.Web, :channel alias Gastronokids.Presence
Déclencher un événement de join asynchrone:
def join("rooms:lobby", payload, socket) do if authorized?(payload) do send self(), :after_join {:ok, socket} else {:error, %{reason: "unauthorized"}} end end
![Page 24: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/24.jpg)
Lier la présence aux channels (2/2)
Garder la trace de la présence après le join et broadcast de la liste initiale:
def handle_info(:after_join, socket) do Presence.track(socket, socket.assigns.user_id, %{ device: "browser", online_at: inspect(:os.timestamp()) }) push socket, "presence_state", Presence.list(socket) {:noreply, socket} end
Note: Il n'est pas nécessaire de gérer la déconnexion / leave. Channels et Presence gèrentcela pour le développeur.
![Page 25: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/25.jpg)
Broadcast des messages de chat
Le callback handle_in sert toujours à assurer la diffusion des messages de chat:
def handle_in("new_msg", payload, socket) do payloadWithUser = %{"body" => payload["body"], "user": socket.assigns.user_id} broadcast! socket, "new_msg", payloadWithUser {:noreply, socket} end
Le callback handle_out n'est pas nécessaire, car nous utilisons l'implémentation par défaut.
![Page 26: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/26.jpg)
user_socket.ex
![Page 27: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/27.jpg)
Assigner le user_id à la socket
Nous étendons la fonction connect/2 dans web/channels/user_socket.ex:
def connect(%{"user_id" => id}, socket) do {:ok, assign(socket, :user_id, id)} end
![Page 28: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/28.jpg)
Le client Javascript socket.js
![Page 29: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/29.jpg)
Mise en place socket / présence
Dans web/static/js/socket.js, nous importons Socket et Presence, et créons unenouvelle socket:
import {Socket, Presence} from "phoenix" let socket = new Socket("/socket", {params: {token: window.userToken, user_id: window.userId}})
Nous lançons la connexion et initialons l'environnement:
socket.connect() let channel = socket.channel("rooms:lobby", {}) let presences = {}
![Page 30: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/30.jpg)
Gestion des événements de présence
La lib Phoenix Presence Javascript gère l'état des présences pour le développeur:
channel.on("presence_state", state => { presences = Presence.syncState(presences, state) render(presences) }) channel.on("presence_diff", diff => { presences = Presence.syncDiff(presences, diff) render(presences) })
![Page 31: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/31.jpg)
Afficher la liste de présence
La lib Phoenix Presence Javascript permet de récupérer et trier la liste des présences:
let listBy = (id, {metas: [first, ...rest]}) => { first.name = id first.count = rest.length +1 return first } let render = (presences) => { let onlineUsers = Presence.list(presences, listBy) let htmlList = onlineUsers .map(user => `<li>${user.name} (${user.count})</li>`) .join("") userList.html(htmlList) }
![Page 32: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/32.jpg)
Gestion des messages
Pour finir, nous gérer la réception et l'envoi des messages:
channel.on("new_msg", payload => { var now = new Date(); messagesContainer.append(`<br/>[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}] ${payload.user}}) chatInput.on("keypress", event => { if(event.keyCode === 13){ channel.push("new_msg", {body: chatInput.val()}) chatInput.val("") } })
![Page 33: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/33.jpg)
L'interface utilisateur
![Page 34: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/34.jpg)
Mise en place du code HTML
Notre code fournit des éléments conteneurs pour les utilisateurs présents et le chat:
<p>Online Users:</p> <ul id="user-list"></ul> <div class="chat"> <div id="messages"></div> <input id="chat-input" type="text"></input> </div>
Pour simplifier, le nom de l'utilisateur vient des paramètres de la page:
<script> window.userId = "<%= if @conn.params["name"], do: @conn.params["name"], else: "Anonymous" %>" </script>
![Page 35: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/35.jpg)
Démo
localhost:4000/?name=Micka%C3%ABl (http://localhost:4000/?name=Micka%C3%ABl)
localhost:4000/?name=JohnDoe (http://localhost:4000/?name=JohnDoe)
localhost:4000/?name=Steve (http://localhost:4000/?name=Steve)
![Page 36: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/36.jpg)
Télécharger le code
Github Gastronokids
github.com/ElixirParis/gastronokids (https://github.com/ElixirParis/gastronokids)
![Page 37: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/37.jpg)
Conclusion
L'ajout du module de Presence complète les channels de Phoenix de manièreredoutablement efficace.
Avec cet ajout, Phoenix devient l'outil le plus complet pour implémenter des applicationsweb temps réel reliant:
Base de données.
Système de templating de pages.
Mise à jour temps réel via un outillage Javascript complet.
Et tout cela, dans un package unique, sans dépendance.
![Page 38: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/38.jpg)
Thank you
Mickaël Ré[email protected] (mailto:[email protected])
http://www.process-one.net/ (http://www.process-one.net/)
@mickael (http://twitter.com/mickael)
![Page 39: Phoenix Presence: Le service temps réel de Phoenix - Paris.ex #8](https://reader033.vdocuments.mx/reader033/viewer/2022051318/58ed7e021a28abd3288b45b5/html5/thumbnails/39.jpg)