Aller au contenu principal
Au-delà du SDK

Cette page n’est pas encore traduite : la version anglaise est affichée.

Sous le capot : transport et hub

Une référence d’architecture, pas une interface que vous appelez. Rien sur cette page n’apparaît dans l’API avec laquelle vous codez : aucun socket, canal, enveloppe ou nouvel essai à gérer de votre côté. Concepts clés nomme les couches ; leur mécanisme n’est décrit qu’ici, pour qu’un architecte puisse vérifier ce que fait le SDK d’une connexion coupée, d’un module désactivé ou d’un message qui doit arriver exactement une fois.

La pile de couches

user spacethe SDK's own businessyour codemodules: rooms, matchmaking, inventory, leaderboards…primitives: events · RPC · data · groupsthe hub: DI and mounting · the user session · state recovery · message QoS · routingtransport adapters: WebSocket · PlayServ UDP · HTTP
La pile de couches : votre code et les modules au-dessus de la ligne ; primitives, hub et transports en dessous

Cinq couches, de haut en bas : l’espace utilisateur, les modules, les primitives, le hub et, sous lui, les adaptateurs de transport. Les deux premières forment l’espace utilisateur ; tout ce qui se trouve en dessous est l’affaire du SDK.

  • L’espace utilisateur, c’est votre code. Il voit les modules, et son vocabulaire s’arrête là.
  • Les modules forment la couche applicative : salles, matchmaking, inventaire, classements. Ils composent un graphe, pas un arbre, et c’est ce graphe que le hub doit résoudre quand l’un d’eux est désactivé (Héritage et composition décrit cette forme elle-même).
  • Les primitives sont la première implémentation, celle à laquelle tout le reste se réfère : données, événements, RPC, groupes. Un module est un assemblage nommé de primitives, auquel s’ajoutent ses propres règles.
  • Le hub est le contrôleur : injection de dépendances, montage des modules, session utilisateur, restauration de l’état, qualité de service des messages, et routage de chaque message entrant vers le module monté pour lui.
  • Les transports sont des adaptateurs vers un protocole. Il en existe plusieurs ; le hub les traite tous de la même manière.

Les transports sont des adaptateurs

Il y aura plus d’un transport, et leurs différences fuiraient sinon dans chaque module :

AxeValeurs possibles
Formepiloté par messages ou par requêtes
Canauxun seul canal ou plusieurs
Étatavec ou sans restauration de l’état de connexion
ProtocoleTCP ou UDP

Concrètement, cela donne aujourd’hui WebSocket, le transport UDP de PlayServ et le HTTP simple. Chacun est un adaptateur qui cache ses propres détails d’implémentation, et chacun expose la même chose vers le haut : une session de transport. Le hub détient une session, jamais un socket ; rien au-dessus de l’adaptateur ne raisonne donc en termes d’interface réseau.

Une seule session de transport à la fois

Un seul canal de transport et une seule session de transport à la fois. Faire tourner un transport backend pour les classements pendant que la session en direct passe par le transport d’un client maître (master-client) n’est pas prévu, et aucune signature d’API ne suppose que plusieurs canaux soient ouverts. Tant qu’une version ultérieure ne dit pas le contraire, le contrat, c’est une session unique.

Le hub masque complètement le transport

Vers le bas, le hub parle l’interface de transport. Vers le haut, il offre l’état, les événements et la session utilisateur. Ni le code des modules ni celui du jeu ne peuvent savoir quel transport se trouve dessous, comment le hub a regroupé un appel, ni ce qu’il a fait pour revenir à un état cohérent après une interruption.

  • La session utilisateur appartient au hub, pas à un module. Reconnexion, reprise et restauration de l’état se font une seule fois, dans le hub, pour tout ce qui y est monté.
  • La QoS des messages appartient au hub, pas au module de données. Enveloppes, nouvelles tentatives et empaquetage relèvent de la mécanique du hub.

QoS des messages : trois niveaux

Un module déclare seulement la garantie de livraison dont il a besoin :

NiveauSignification
at least oncerenvoyé jusqu’à l’acquittement ; le destinataire tolère les doublons
at most onceenvoyé une fois, jamais renvoyé ; une perte est acceptable
exactly oncedédupliqué et acquitté ; le plus coûteux, réservé aux cas qui l’exigent

La façon de tenir cette garantie regarde le hub, ni le module ni vous.

DI, montage et modules désactivés

Le hub instancie les modules et les monte — à la racine ou dans un espace de noms — en résolvant les dépendances de chacun envers les primitives et les autres modules. Un build qui n’a pas besoin d’un module ne le monte pas. Le montage se fait par espace de noms, et un second module qui revendique un point de montage déjà occupé est rejeté au montage : la composition échoue à ce moment-là, jamais au premier appel.

Comme les modules forment un graphe, en désactiver un a des conséquences en aval, et le hub emprunte exactement l’une de deux voies :

  1. Désactiver la chaîne dépendante. Tout module qui a besoin du module manquant est désactivé lui aussi, et ses interfaces sont absentes au lieu d’échouer.
  2. Déclarer un fonctionnement dégradé. Les modules dépendants restent montés et annoncent ce qu’ils ne savent plus faire.

Il n’y a pas de troisième voie : un module monté n’abandonne jamais en silence les opérations qu’il ne peut plus effectuer, si bien qu’une dépendance désactivée est toujours observable.

Ce qui reste au-dessus de la ligne

Toutes les promesses des pages de module sont tenues au-dessus de la ligne : modifier une entité, c’est faire l’opération réseau ; un hook est une fonction typée ; rejoindre une salle tient en un appel. Les noms des couches peuvent vous parvenir — Concepts clés renvoie ici —, mais rien sous la ligne n’est un appel que fait votre code. Ces couches existent pour que les promesses du dessus survivent à un changement de transport.

Ce que vous rencontrerez vraiment — le contexte de livraison dans lequel tournent vos handlers, le moment où un handle prend fin, et l’implémentation en mémoire contre laquelle vous testez — se trouve une page plus haut : Threads, cycle de vie et tests.