0.3.4-rc.1

This commit is contained in:
2026-09-21 19:53:50 +02:00
parent 881d5afacd
commit f270ed8f86
11 changed files with 885 additions and 18 deletions

View File

@@ -0,0 +1,49 @@
<!-- file: crates/common/game-realtime-websocket-lib/README.md -->
<!-- version: 1 -->
# game-realtime-websocket-lib
Backend WebSocket de référence pour le contrat `game-realtime-transport-lib`, fondé sur Tokio et `tokio-tungstenite`.
## Responsabilité
La crate possède :
- connexion client `ws://` ;
- listener serveur TCP + upgrade WebSocket ;
- types concrets `WebSocketConnection`, `WebSocketSender` et `WebSocketReceiver` ;
- mapping WebSocket vers le contrat binaire transport-neutral ;
- limites de message/frame/write-buffer ;
- deadlines connect/handshake, send et close ;
- tracing du domaine `games::realtime::websocket` ;
- mapping des erreurs Tungstenite vers `TransportErrorKind`.
Elle ne possède pas le runtime Tokio : le consommateur crée et exécute son runtime. La crate ne lance ni runtime global, ni thread runtime privé, ni task backend détachée pour une connexion de base.
## Frontières
Le backend transporte des octets opaques. Il ne connaît ni joueur, ni room, ni tick, ni snapshot, ni codec wire, ni protocole de session.
Les messages Text ne font pas partie du contrat et sont rejetés comme erreur de protocole. Ping/Pong reste un détail WebSocket. Une fermeture distante propre devient `TransportReceive::Closed`.
La baseline active utilise `ws://`. Aucune feature TLS de `tokio-tungstenite` n'est activée ; une politique `wss://` directe n'est pas introduite tant qu'un besoin produit et une stratégie de certificats ne sont pas démontrés.
## Configuration
`WebSocketConfig::default()` fournit des bornes produit explicites :
```text
message maximum 1 MiB
frame maximum 1 MiB
write buffer target 64 KiB
write buffer maximum 2 MiB
connect/handshake 10 s
send 5 s
close 2 s
```
Les builders `with_*` permettent d'adapter ces limites avant `connect_with_config` ou `WebSocketListener::bind_with_config`. `validate()` refuse les configurations incohérentes avant l'établissement réseau.
## Utilisation
Voir [`USAGE.md`](USAGE.md) pour les points d'entrée client/serveur, la configuration et le smoke de référence.

View File

@@ -0,0 +1,78 @@
<!-- file: crates/common/game-realtime-websocket-lib/USAGE.md -->
<!-- version: 1 -->
# Utilisation — backend realtime WebSocket
## Préconditions
Le consommateur possède le runtime Tokio. `game-realtime-websocket-lib` utilise Tokio pour les sockets et deadlines mais ne crée jamais son propre runtime.
Le contrat transport-neutral est fourni par `game-realtime-transport-lib`. Pour appeler `split`, `send`, `receive` et `close`, importer les traits correspondants dans le module consommateur selon les règles Rust du dépôt.
## Client
Le point d'entrée simple est :
```text
game_realtime_websocket_lib::connect("ws://host:port/path")
```
La fonction retourne une `WebSocketConnection`. La connexion est ensuite consommée par `RealtimeConnection::split()` pour obtenir un sender et un receiver indépendants.
Pour une configuration spécifique, construire `WebSocketConfig`, valider ses invariants puis utiliser :
```text
game_realtime_websocket_lib::connect_with_config(endpoint, config)
```
## Serveur
Créer d'abord une adresse `SocketAddr`, puis binder :
```text
WebSocketListener::bind(address)
```
ou :
```text
WebSocketListener::bind_with_config(address, config)
```
`local_addr()` permet de connaître l'adresse réellement allouée, notamment après bind sur `127.0.0.1:0`. `accept().await` attend ensuite un peer TCP et effectue l'upgrade WebSocket dans la deadline configurée.
## Émission et réception
Un message applicatif est encapsulé dans `TransportMessage::new(Vec<u8>)`. Le sender refuse localement un payload dépassant les bornes configurées avant écriture.
`receive()` retourne :
- `TransportReceive::Message` pour un payload binaire ;
- `TransportReceive::Closed` pour une fermeture distante propre ;
- `TransportError` pour une erreur réseau/protocole, un timeout ou une limite dépassée.
Une frame Text reçue est une erreur de protocole : elle n'est jamais convertie en bytes métier.
## Fermeture
`RealtimeSender::close()` initie un close WebSocket propre et applique la deadline de fermeture configurée. Une task/future annulée n'est pas assimilée à un close handshake réussi.
## Smoke local
Le launcher de validation public utilise uniquement les API exposées par les deux crates realtime :
```bash
cargo run -p game-realtime-websocket-smoke
```
Il bind `127.0.0.1:0`, connecte un client réel, échange un payload binaire dans les deux sens, initie un close propre et doit terminer avec :
```text
game-realtime-websocket-smoke: PASS
```
Le smoke ne dépend ni d'Internet, ni d'un port fixe, ni d'un serveur externe.
## Limites intentionnelles
Cette crate n'est pas un protocole multijoueur. Authentification, versionnement wire, session joueur/room, heartbeat métier, resynchronisation, snapshots/deltas et simulation authoritative appartiennent aux couches supérieures et restent hors de son contrat.