Some checks failed
Build & Deploy / build-and-deploy (push) Failing after 8s
Includes React PWA frontend, WebSocket signaling server, shared types, K8s manifests, Gitea CI/CD workflow, nginx config, and Dockerfiles. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
Architecture AnyDrop
Vue d'ensemble
AnyDrop repose sur trois briques :
- Client (web, extension, desktop, mobile) — interface utilisateur + moteur WebRTC
- Serveur de signaling — met en relation les pairs, ne voit jamais les fichiers
- Serveurs STUN/TURN — aident à établir la connexion P2P à travers les NAT/firewalls
┌──────────┐ WebSocket ┌────────────────┐ WebSocket ┌──────────┐
│ Client A │ ────────────────────▶ │ Signaling │ ◀──────────────────── │ Client B │
└──────────┘ │ Server │ └──────────┘
│ └────────────────┘ │
│ │
│ ═══════ WebRTC DataChannel (P2P chiffré DTLS) ═══════ │
└─────────────────────────────────────────────────────────────────────────────┘
(les fichiers transitent uniquement ici)
Le serveur de signaling
Responsabilités
- Accepter les connexions WebSocket entrantes
- Attribuer un
peerIdunique et undisplayName(nom animal aléatoire) à chaque client - Placer le client dans la ou les rooms appropriées :
- Room LAN : hash de l'IP publique de la connexion
- Room publique : code court fourni dans l'URL (ex:
/x7k)
- Relayer les messages de signaling (
offer,answer,ice-candidate) entre pairs d'une même room - Notifier
peer-joined/peer-left - Expirer les rooms publiques inactives (10 min)
Ce que le serveur ne fait PAS
- ❌ Ne stocke aucun fichier ni contenu échangé
- ❌ Ne log pas les IPs dans des fichiers persistants
- ❌ N'a pas de base de données
- ❌ N'a pas d'authentification
Les clients
Tous les clients (web, extensions, desktop, mobile) implémentent le même protocole de signaling et la même logique WebRTC. Le code shared/ exporte les types de messages communs pour garantir la cohérence.
Couche abstraction P2P
On utilise simple-peer pour masquer la complexité de l'API WebRTC native :
const peer = new SimplePeer({ initiator: true, trickle: true });
peer.on('signal', data => sendViaWebSocket(data)); // envoyer offer/ICE
peer.on('connect', () => sendFile(file)); // connexion établie
peer.on('data', chunk => reassemble(chunk)); // chunks reçus
Découpage des fichiers
- Chunk size : 16 Ko (compromis débit/mémoire)
- Header JSON initial :
{ name, size, mime, id } - Puis envoi séquentiel avec backpressure (
peer._channel.bufferedAmount < 1MB) - Fin de fichier : chunk spécial
{ eof: true, id } - Récepteur : accumule dans un
Blob[]puisnew Blob(chunks, { type })
STUN et TURN
STUN (Session Traversal Utilities for NAT)
Gratuit, quasi-gratuit en bande passante (quelques paquets). Sert uniquement à ce que le client découvre sa propre IP publique + port NAT, pour l'inclure dans les ICE candidates.
Serveurs utilisés : stun.l.google.com:19302, stun1.l.google.com:19302.
TURN (Traversal Using Relays around NAT)
Fallback quand le P2P direct échoue (~10-20% des cas, surtout en entreprise / 4G). Le trafic est alors relayé par le serveur TURN → coût bande passante réel.
- V1 : Open Relay (gratuit, 500 Go/mois) — suffisant pour un lancement
- Plus tard : coturn auto-hébergé sur un VPS
Déploiement cible
| Composant | Hébergement | URL |
|---|---|---|
| Front web (PWA) | Vercel / Netlify | anydrop.arthurbarre.fr |
| Signaling | Railway / Fly.io | ws.anydrop.arthurbarre.fr |
| STUN | Google (gratuit) | stun.l.google.com:19302 |
| TURN | Open Relay → coturn | turn.anydrop.arthurbarre.fr |