Portail d'enseignement

E Suong
E Suong

Explorer les ressources

Accueil

Documentation technique

Parties privées et protocole

Fiche de référence du code : fonctionnement, formats et limites. La disponibilité publique dépend de la version publiée.

Sommaire de la fiche

État public de référence au 29 octobre 2026 : 3acbb8d, neuf jeux de stratégie publiés, dont Shogi et Mini Shogi. Les bilans de tests datés à sept ou huit jeux restent historiques. La phase 1 comptes/barème n’est pas déclarée publiée par cette fiche ; les fonctions élèves/classes et nouveaux jeux restent bêta.

État vérifié le 27 octobre 2026. Shogi est publié ; sa migration ciblée a été appliquée. La référence publique comprend aussi Mini Shogi, publié, sur une page et des salons distincts. Les neuf jeux de stratégie de la branche proposent le mode local et le mode 1 contre 1 à distance : L Game, Hex, Juniper Green, Petits carrés, Reversi, Jeu du moulin, Méta Morpion, Shogi et Mini Shogi. Les défis LN et l’Escape Game ne sont pas concernés. Aucun ordinateur, compte joueur, classement, spectateur ni recherche publique d’adversaire n’est ajouté.

Pour l’installation sur un vrai serveur, suivre Déployer les jeux à distance (../DEPLOIEMENT_JEUX.md), en complément d’Installation (../INSTALLATION.md). Cette fiche décrit le comportement et le contrat technique ; le guide décrit l’exploitation et la recette avant ouverture.

Parcours et autorité de l’hôte

  1. Ouvrir le jeu et descendre à l’encart Jouer à distance, situé après les règles et les paramètres sur les neuf pages. Il est déplié par défaut et peut être replié avec son bouton. Cliquer sur Créer une partie privée. Les réglages locaux courants sont repris pour ce nouveau salon. Entrer dans un salon remplace la partie locale.
  2. Transmettre le code de dix caractères ou le lien. Le lien préremplit le code ; le deuxième joueur clique sur Rejoindre. Le code est consommé dès que cette place est occupée.
  3. L’hôte vérifie les options sous les règles. Dans les six nouvelles intégrations, Appliquer les réglages les transmet aux deux joueurs ; Reversi applique directement chaque changement de contrôle. Seul l’hôte dispose des commandes actives. Les refus sont aussi vérifiés côté serveur.
  4. Lorsque les deux joueurs sont connectés, l’hôte clique sur Lancer la partie. Avant cela, les coups sont bloqués.
  5. Chaque coup est validé par le serveur et transmis aux deux écrans. Les entrées sont bloquées pendant une demande, une coupure, l’envoi d’une commande ou le tour adverse.

Les places authentifiées restent hôte / rôle 0 et invité / rôle 1. L’hôte commence la première partie, puis chaque nouvelle partie acceptée alterne le premier joueur : invité, hôte, invité… Celui qui commence prend le joueur 1 du moteur (index 0), bleu au départ, sauf Shogi monochrome ; l’autre prend le joueur 2, rouge au départ (Gote au Shogi). Les numéros/couleurs peuvent donc changer entre parties, sans transfert des droits de l’hôte. Aucun tirage au sort. À Hex, l’échange change les couleurs et les bords, jamais les identités ni le rôle d’hôte. Le bandeau indique la couleur actuelle de chaque joueur. Le code n’est pas un compte ni une clé de reconnexion : ne le transmettre qu’à l’adversaire attendu. Si une ancienne place est restaurée en ouvrant une autre invitation du même jeu, quitter d’abord l’ancien salon.

Réglages disponibles

Jeu / identifiant API Réglages de l’hôte Modification pendant une partie
Shogi / shogi Aucun : règles fixes, paramètres {} Affichage et aide personnels, modifiables dans le navigateur sans commande réseau
L Game / l-game maxTurns : entier 1–200, défaut 20 Nouvelle partie acceptée nécessaire
Hex / hex size : 7/9/11/13, défaut 11 ; swapEnabled : booléen, défaut vrai Nouvelle partie acceptée nécessaire
Juniper Green / juniper-green limit : 16/49/100, défaut 16 ; showMoves : booléen, défaut faux L’aide peut changer pour les deux joueurs ; taille lors d’une nouvelle partie
Petits carrés / petits-carres Aucun ; grille fixe de 6 × 7 carrés Aucun
Reversi / reversi size : 8/6, défaut 8 ; showMoves : booléen, défaut faux L’aide peut changer pour les deux joueurs ; taille lors d’une nouvelle partie
Moulin / moulin maxTurns : entier 1–500, défaut 100 Nouvelle partie acceptée nécessaire
Méta Morpion / meta-morpion Aucun ; neuf grilles 3 × 3 Aucun

Le plafond de tours des jeux concernés compte les tours individuels des deux joueurs, pas les paires de tours. Les aides structurelles du Moulin et du Méta Morpion restent celles du jeu local, sans nouvelle option. Les réglages sont validés strictement : nombres entiers/plages, booléens réels, aucun champ étranger au jeu. Même l’hôte ne peut pas changer une règle fixe au milieu d’une partie. L’invité peut demander de recommencer, mais uniquement avec les réglages actuels de l’hôte ; les options éventuellement injectées dans sa requête sont ignorées.

Fin de partie et alternance

Une victoire ou un nul ne ferme pas le salon : le plateau final reste affiché, les coups sont bloqués, mais les joueurs peuvent demander une annulation ou une Nouvelle partie du même jeu. Cette dernière exige l’accord adverse. Les salons terminés comptent toujours dans la capacité et expirent aux délais habituels (inactivité, déconnexion, durée absolue). Rejouer ne remet pas à zéro la durée de vie du salon.

L’alternance intervient uniquement à l’acceptation d’une nouvelle partie, que la précédente soit terminée ou interrompue. Une proposition refusée, retirée ou expirée ne change pas le premier joueur ; une annulation de coup et une reconnexion non plus. Une commande d’acceptation répétée à l’identique ne fait pas alterner deux fois. L’identité du demandeur et celle du gagnant sont sans effet. Une nouvelle création de salon repart avec l’hôte en premier. À Hex, l’échange des couleurs ne modifie pas le premier joueur de la prochaine partie. Les modes locaux conservent leur fonctionnement.

Annulation, nouvelle partie et tours composés

Annuler un coup envoyé au serveur et recommencer nécessitent l’accord de l’autre joueur. Une demande suspend le jeu, affiche les nouveaux réglages le cas échéant et expire après une minute. Son auteur peut la retirer. Un refus, un retrait ou l’expiration conserve le plateau. Le demandeur ne peut pas accepter sa propre demande. L’hôte décide des paramètres mais ne peut pas effacer unilatéralement une partie en cours. Quitter le salon est un abandon explicite distinct.

Jeu Commande de jeu (op: "play") Unité annulée après accord
L Game action: {type: "l", cells: [quatre indices]}, puis action: {type: "finish", neutralMove: null ou {index,to}} Tour complet avant le L, avec le pion éventuel ; possible aussi pendant la phase neutre
Hex action: {type: "place", cell} ou {type: "swap"} Dernière pose ou échange, avec restauration des couleurs et du chemin
Juniper Green number (1 à la taille de grille) Un nombre, avec restauration de la dernière valeur et de la victoire
Petits carrés edge (0–96) Un trait avec ses carrés et scores, même si le joueur doit rejouer
Reversi cell (index de case) Une pose avec retournements, passe et fin éventuelle
Moulin action: {type: "place",to}, {type: "move",from,to} ou {type: "capture",at} Pose/déplacement ET capture éventuelle ; restaure aussi les compteurs de répétition
Méta Morpion board et cell (0–8) Une pose avec grille imposée, résultats locaux et fin globale

Les indices sont ceux des moteurs, documentés dans leurs fiches. Un choix encore non envoyé (cases du L sélectionnées, pion du Moulin sélectionné, destination du pion neutre préparée) reste local et peut être effacé sans accord. Il n’est pas sauvegardé lors d’un rechargement. Une phase déjà validée (L déplacé, capture obligatoire du Moulin) est conservée sur le serveur et restituée à la reconnexion. Les coups ne sont pas alternés artificiellement : le Moulin garde le joueur pendant la capture, le L Game pendant le pion, les Petits carrés après fermeture, et Reversi gère ses passes.

Connexion, fermeture et données

Une coupure suspend les coups. La place est réservée cinq minutes par défaut, pendant lesquelles recharger le même onglet retrouve le plateau. La fermeture explicite du salon, confirmée dans l’interface, ferme la partie des deux joueurs et libère sa place dans la capacité globale. Fermer définitivement un onglet peut perdre sa clé ; le code d’invitation consommé ne permet pas de reprendre une place. Une duplication d’onglet peut copier la même clé selon le navigateur : ce n’est pas un deuxième joueur. Pour tester à deux sur une machine, ouvrir un onglet neuf avec l’invitation.

Le navigateur utilise sessionStorage, avec {roomId,token} dans l’une de ces clés :

mini-shogi-online-seat-v1
shogi-online-seat-v1
l-game-online-seat-v1
hex-online-seat-v1
juniper-green-online-seat-v1
petits-carres-online-seat-v1
reversi-online-seat-v1
moulin-online-seat-v1
meta-morpion-online-seat-v1

Une place par jeu et par onglet ; les neuf jeux de la branche partagent le même service et le même plafond de salons. Ces clés ne contiennent pas une sauvegarde du plateau et ne sont pas gérées par la page Connexion. Quitter ou recevoir la fermeture du salon efface la clé concernée. Si le stockage est refusé, la partie peut se jouer dans l’onglet ouvert, mais sa reprise n’est pas garantie ; l’interface le signale. Changer de domaine, protocole, port, profil ou appareil ne transporte pas cette place.

Salons, plateaux, historiques, réglages et limitations de fréquence restent en mémoire d’un seul processus Node. Aucun coup n’est écrit sur disque. Un arrêt, crash, redémarrage ou déploiement les perd définitivement ; une sauvegarde des fichiers du site ne les restaure pas. Aucun transfert d’hôte ni remplacement d’un adversaire déconnecté. Les parties locales continuent de fonctionner sans envoyer leurs coups au serveur.

Sources et protocole

Fichier Responsabilité
src/lib/online/games.mjs Identifiants, rubrique associée, valeurs par défaut, champs et validation des options ; utilisable dans le navigateur
src/lib/online/adapters.mjs Appels aux moteurs purs, détection de fin et point d’entrée d’historique annulable
src/lib/online/rooms.mjs État des salons, authentification de place, capacité, présence, historique, consentements, révisions et délais
src/lib/online/http.mjs Validation de corps/origine, réponses, flux SSE et nettoyage des connexions
src/pages/api/online/index.ts Création/entrée, contrôle de la rubrique demandée
src/pages/api/online/[id].ts Abonnement et commandes ; la rubrique est déduite du salon authentifié, jamais d’un jeu fourni librement avec le coup
src/lib/online/client.mjs Abonnement, reconnexion, délais, rejet des réponses périmées
src/components/OnlineLobby.svelte / OnlineSettings.svelte Interface partagée des six jeux ajoutés ; Reversi conserve son interface initiale branchée sur le même service
Les composants/moteurs de jeu Rendu et règles existants ; aucun moteur réseau divergent

SSE sert à recevoir ; POST sert à jouer. Il n’y a ni WebSocket, ni dépendance réseau supplémentaire, ni port séparé à ouvrir. Les pages et API sont sur la même origine. GET SSE envoie data: {type:"state",snapshot:...} ou data: {type:"closed",message:...}, séparés par deux sauts de ligne. Chaque événement d’état contient un instantané complet : aucun historique d’événements à rejouer après une coupure. Un commentaire de maintien de connexion est envoyé toutes les quinze secondes. Le client renouvelle un flux silencieux pendant quarante secondes, avec attente progressive de 1 à 10 secondes en cas d’échec. Les mutations et l’entrée ont un délai client de dix secondes.

Le client n’applique pas un coup de façon optimiste : il attend l’état validé. Il ne rejoue jamais automatiquement une mutation dont la réponse a été perdue. Les instantanés plus anciens que la dernière révision sont ignorés ; une connexion remplacée ne doit plus appliquer ses réponses. Durant la restauration des six nouvelles interfaces, le plateau local transitoire est rendu inactif jusqu’à réception du salon.

Endpoints

Requête Corps / authentification Réponse normale
POST /api/online {op:"create",game,settings} {roomId,token,snapshot}
POST /api/online {op:"join",game,code} Même format, rôle invité
GET /api/online/:roomId Authorization: Bearer <token> Flux SSE initial, puis changements
POST /api/online/:roomId Même en-tête ; {op,revision,actionId,...} Instantané courant, ou {closed:true} après départ

Commandes authentifiées : settings avec options complètes, start, play selon le tableau des jeux, request avec kind:"undo"|"restart" et options si hôte, respond avec requestId et accept booléen, cancel, leave. actionId comprend 16–80 caractères alphanumériques/tirets ; le client utilise un UUID. Aucun import de plateau fourni par le navigateur.

État public : roomId, gameType, role, starterRole, playerIndex, revision, phase (lobby/playing/finished), settings, game, pending, hasGuest, online, canUndo, lastPlayer, inviteCode (hôte avant entrée seulement), disconnectSeconds. Une demande contient id, kind, by, settings et expiresAt. Les secrets de place et l’historique complet n’y figurent pas. Le moteur Moulin transmet ses comptes de répétition dans game.positions, qui font partie de l’état de règle.

role identifie la place authentifiée (0 hôte, 1 invité), starterRole la place qui commence cette partie et playerIndex = role XOR starterRole son joueur dans le moteur. Les réglages, invitations, présences online et auteurs pending.by utilisent toujours les rôles ; le trait game.player, lastPlayer, les scores, gagnants et couleurs utilisent les indices moteur. Pour Hex, la couleur affichée est game.colors[playerIndex]. Le serveur déduit ces valeurs : aucun champ envoyé par le client ne permet de choisir son camp. Les interfaces doivent comparer le trait à playerIndex, jamais à role. starterRole est conservé hors de l’historique des coups et bascule à chaque nouvelle partie acceptée. Les salons de développement créés avant ce champ sont interprétés avec starterRole = 0.

Les actions sont synchrones dans un processus ; elles vérifient l’identité au trait et une révision exacte. Une révision périmée donne 409. Les 64 derniers identifiants de commande par place permettent d’ignorer une répétition strictement identique ; réutiliser un identifiant pour un autre corps donne 409. Ce mécanisme n’est ni un journal durable ni une garantie entre redémarrages. Pour L Game et Moulin, l’historique s’ajoute au début d’un tour, jamais à sa deuxième phase ; annuler une demande n’altère pas l’historique.

Accès, limites et erreurs

Chaque route contrôle le niveau et la disponibilité de la rubrique du jeu concerné selon le catalogue et les cookies. La clé de salon ne donne pas accès à un jeu réservé. Les connexions SSE déjà ouvertes ne réévaluent pas les droits à chaque notification ; les POST et reconnexions les vérifient. Une révocation immédiate de tous les abonnements ouverts n’est pas implémentée. Les commandes de gestion du site restent administratives.

Code aléatoire de 40 bits ; identifiant de salon de 128 bits ; clé de place de 256 bits. Seul le hachage SHA-256 de cette dernière est conservé côté serveur. La clé passe dans Authorization, jamais dans l’URL. Le code d’invitation utilise le fragment #join=..., retiré après lecture. Les POST exigent une origine identique ; les requêtes explicitement cross-site sont refusées. Pas de CORS ouvert. Utiliser HTTPS en production ; ne pas journaliser les clés ni les corps d’entrée/réponse.

Protection Limite actuelle
Corps JSON 4 Kio, y compris réception par fragments
Abonnements par place 3
Commandes par place 90 par minute
Créations par adresse 30 par 10 minutes
Tentatives d’entrée par adresse 60 par 10 minutes
Requêtes à la route d’entrée par adresse 120 par minute
Requêtes de salon par adresse 600 par minute
Clés de compteurs mémoire 2 000, expirables

Les adresses proviennent de Astro.clientAddress. Dans la version installée, Astro peut reprendre X-Forwarded-For si l’hôte est validé : le proxy doit écraser cet en-tête et le port Node ne doit pas être public. Ne pas présenter la simple liste de domaines autorisés comme une authentification du proxy. Plusieurs élèves derrière une même adresse peuvent partager un quota. Ces plafonds ne constituent pas une protection complète contre un trafic massif. Voir la configuration vérifiée dans le guide de déploiement (../DEPLOIEMENT_JEUX.md).

Statut Interprétation
400 Paramètres/action/code de commande invalides ou coup illégal
403 Origine, accès à la rubrique, rôle ou tour non autorisé
404 Code invalide/complet/expiré, salon ou clé de place invalide
409 État périmé, joueur absent, phase ou demande incompatible
413 / 415 Corps trop volumineux / format autre que JSON
429 Quota ou nombre de connexions atteint
503 Capacité de salons atteinte
500 Erreur serveur inattendue, message générique

Le middleware peut répondre en texte à une origine interdite ; ne pas supposer que toutes les erreurs amont/proxy sont JSON. Une erreur réseau ne prouve pas qu’un coup a été refusé : attendre la resynchronisation avant de rejouer.

Configuration mémoire et délais

Variables facultatives lues lors de la création du service. Entiers strictement positifs ; valeur absente/invalide → défaut. 0 ne désactive pas la limite. En production, npm start charge .env. Modifier ces valeurs nécessite un redémarrage, qui termine les salons.

Variable Défaut Portée
GAME_MAX_ROOMS 20 Total des jeux (neuf en production), salons en attente, en cours et terminés compris
GAME_WAITING_MINUTES 10 Depuis la création, tant que le second joueur n’a pas rejoint
GAME_IDLE_MINUTES 30 Depuis la dernière action acceptée ; les battements réseau n’entretiennent pas le salon
GAME_RECONNECT_MINUTES 5 Depuis la perte de la dernière connexion d’une place, ou sa réservation sans abonnement
GAME_LIFETIME_HOURS 4 Durée absolue depuis la création, même si l’on rejoue dans le même salon

La première échéance atteinte ferme le salon. Nettoyage toutes les cinq secondes et lors des accès. Une nouvelle partie ne réinitialise pas la durée absolue. Une place d’hôte jamais connectée expire donc en cinq minutes, avant les dix minutes d’attente. Les demandes de consentement expirent après 60 secondes (constante, pas de variable exposée). Les salons terminés restent disponibles pour annuler/rejouer jusqu’à leur expiration ; ils comptent encore dans la capacité. 20 est un réglage initial, pas une charge maximale mesurée.

Étendre ou modifier le service

Ajouter un jeu demande une définition publique dans games.mjs, un adaptateur serveur (initial, play, over, checkpoint) et une interface raccordée. La rubrique indiquée dans la définition détermine les droits API. Valider les commandes à l’entrée puis dans le moteur ; ne jamais confier au client la victoire, le camp autorisé ou le nouvel état. Définir la transaction annulable et le comportement de reconnexion avant de coder. Les aides visuelles live peuvent changer pendant la partie ; les autres options seulement en attente ou par nouvelle partie consentie.

RoomService accepte horloge et durées injectables. sharedRooms() conserve un singleton global ; en développement, son prototype est actualisé lors d’un appel pour prendre en compte le rechargement de code. Cette commodité ne remplace pas un redémarrage de production ni une migration d’état. Ne pas exploiter plusieurs processus ou réplicas : état et plafond seraient indépendants. Une évolution multi-instance nécessite stockage partagé transactionnel, diffusion entre instances et quotas partagés ; la reprise après redémarrage nécessite en plus une persistance. Aucun de ces mécanismes n’est implémenté.

Validation du 27 octobre 2026

200 tests passent, compilation réussie. tests/online-rooms.test.mjs (10 tests) couvre le service, les secrets, révisions, doublons, consentements, délais, quotas et contrôle des corps. tests/online-games.test.mjs (23 tests) couvre une partie complète distante des sept moteurs avec états identiques, annulation après fin, autorité de l’hôte, options invalides, codes propres au jeu, phases du L Game, capture du Moulin, échange de Hex, double carré, aide Juniper et grille imposée du Méta Morpion. Neuf tests supplémentaires couvrent l’alternance sur les sept jeux : parties complètes avec invité en premier, interdiction du mauvais camp même si des champs sont injectés, droits de l’hôte inchangés, annulation, reconnexion, fin sans fermeture, refus/retrait/expiration, acceptation répétée et échange de Hex lors d’une revanche. Les tests propres aux moteurs restent la référence détaillée des règles.

tests/online-all-http-smoke.mjs vérifie les sept jeux sur une vraie instance : entrée, droits hôte/invité, coup, deux flux, déconnexion/reconnexion, annulation consentie, deux nouvelles parties alternées avec contrôle du camp autorisé et fermeture. Exécuté avec succès sur le serveur de développement et le serveur compilé sur un port distinct, puis avec des en-têtes de proxy HTTPS simulés sur ce dernier. Cela ne vérifie ni certificat TLS réel ni Nginx installé. L’ancien online-http-smoke.mjs reste une recette Reversi plus courte. Instructions et précautions dans le guide de déploiement.

Navigateur, deux onglets : les six jeux ajoutés ont été rejoints et joués. L Game : limite à 1, phase neutre après rechargement, nul et annulation du tour. Hex : 7 × 7, échange, hôte devenu rouge, coup rouge et refus d’annulation. Moulin : limite 5, capture après rechargement, nul et annulation complète. Juniper : aide hôte visible chez l’invité, victoire 12→1→13 et nouvelle grille 49 acceptée. Petits carrés : double capture, maintien du joueur et annulation des scores. Méta Morpion : renvoi imposé et nouvelle partie sans option. Reversi avait déjà sa recette navigateur lors de la première intégration ; il est revérifié par les recettes serveur communes.

Recette d’alternance au navigateur : Reversi, revanche acceptée, invité bleu autorisé à poser, hôte rouge bloqué au premier coup, reconnexion de l’invité conservant son camp. Hex (interface partagée), revanche initiée par l’invité, premier coup invité, échange par l’hôte, coup rouge invité, deuxième revanche et premier coup revenu à l’hôte. Les encarts distants sont après règles/paramètres et ouverts par défaut.

Restent à effectuer sur l’hébergement retenu : recette publique sur deux réseaux, contrôle du véritable proxy/CDN et des certificats, tactile sur appareil, tests de charge et dimensionnement. Aucun déploiement public réalisé. Ni la réussite des tests locaux ni une réponse HTTP 200 ne dispensent de cette recette.

Extension Shogi : action:{type:"move",from,to,promote} ou {type:"drop",piece,to}, ainsi que {type:"resign"} / {type:"declare"}, transmis avec op:"play". Un coup complet (promotion/capture comprise) est un point d’annulation. Le moteur de fin de partie est décrit dans Shogi. monochrome:true adapte seulement le bandeau du salon à Sente/Gote. Aucun affichage/aide personnel n’est inclus dans les réglages partagés. Les anciennes recettes datées restent l’historique des sept jeux précédents.

Extension Mini Shogi publiée : identifiant mini-shogi, rubrique jeux-mini-shogi, réglages {}, monochrome. Même protocole de déplacement/parachutage/abandon, indices 0–24 ; déclaration d’entrée du roi refusée. Préférences personnelles avec préfixe mini-shogi, aucune collision avec Shogi. Invitations incompatibles entre variantes. Lors d’une répétition ordinaire, le camp Sente perd même s’il correspond à l’invité après revanche. Le scénario HTTP/SSE actuel couvre neuf jeux ; anciens bilans datés conservés. Règles et stockage.

← Retour à la documentation