0.3.4-rc.1
This commit is contained in:
42
crates/common/game-realtime-transport-lib/README.md
Normal file
42
crates/common/game-realtime-transport-lib/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
<!-- file: crates/common/game-realtime-transport-lib/README.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# game-realtime-transport-lib
|
||||
|
||||
Contrat realtime transport-neutral de `games.sasedev`. La crate définit uniquement la forme minimale d'une connexion établie, de ses moitiés d'envoi/réception, des payloads binaires opaques et des erreurs stables visibles par les couches supérieures.
|
||||
|
||||
## Responsabilité
|
||||
|
||||
La crate possède :
|
||||
|
||||
- `TransportMessage`, buffer binaire possédé ;
|
||||
- `TransportReceive`, qui distingue message reçu et fermeture distante propre ;
|
||||
- `RealtimeConnection`, `RealtimeSender` et `RealtimeReceiver` ;
|
||||
- `TransportError` et `TransportErrorKind` comme catégories backend-neutral.
|
||||
|
||||
Elle ne possède pas :
|
||||
|
||||
- l'établissement d'une connexion réseau ;
|
||||
- Tokio ou un autre runtime ;
|
||||
- WebSocket, WebTransport, QUIC, HTTP ou TLS ;
|
||||
- un codec wire ;
|
||||
- une session joueur/room ;
|
||||
- la synchronisation gameplay ou la simulation authoritative.
|
||||
|
||||
## Contrat async
|
||||
|
||||
`RealtimeConnection::split()` consomme une connexion établie et retourne des moitiés d'envoi et de réception indépendantes. Les opérations async sont exposées par des futures associées GAT plutôt que par `async-trait` ou `Box<dyn Future>`.
|
||||
|
||||
Le contrat n'impose volontairement aucune borne `Send` aux futures. Un backend natif peut fournir des futures `Send`, tandis qu'un futur backend navigateur/WASM ne doit pas être exclu par une contrainte de threading qui ne relève pas de l'abstraction transport.
|
||||
|
||||
## Sémantique
|
||||
|
||||
Les payloads sont toujours binaires et opaques. Une couche supérieure pourra ultérieurement leur appliquer un codec wire ou un protocole de session sans modifier cette crate.
|
||||
|
||||
Une fermeture distante propre est représentée par `TransportReceive::Closed`. Elle n'est pas convertie en erreur I/O générique. Les erreurs utilisent une catégorie stable (`Timeout`, `MessageTooLarge`, `Backpressure`, `Protocol`, etc.) et un détail de diagnostic, sans exposer le type d'erreur du backend concret.
|
||||
|
||||
## Dépendances et sens d'ownership
|
||||
|
||||
Cette crate ne dépend d'aucun backend realtime. Les implémentations concrètes dépendent d'elle, jamais l'inverse.
|
||||
|
||||
Le premier backend de référence est `game-realtime-websocket-lib`. Le POC WebTransport/QUIC prévu ensuite doit d'abord challenger cette même frontière avant toute généralisation supplémentaire.
|
||||
49
crates/common/game-realtime-websocket-lib/README.md
Normal file
49
crates/common/game-realtime-websocket-lib/README.md
Normal 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.
|
||||
78
crates/common/game-realtime-websocket-lib/USAGE.md
Normal file
78
crates/common/game-realtime-websocket-lib/USAGE.md
Normal 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.
|
||||
Reference in New Issue
Block a user