docs(blog): add “Cached ID reconnect” post in 7 languages with cover

- Add multi-language post “Cached ID reconnect: auto rejoin and resume”:
    zh, en, ja, ko, de, fr, es under: frontend/content/blog/cached-id-reconnect/*.mdx
  - Include cover asset: frontend/public/blog-assets/cached-id-reconnect.webp
  - Describe receiver auto-join, reconnect workflow, and resume behavior.
  - Tag with WebRTC/P2P/reconnect for discoverability.
This commit is contained in:
david_bai
2025-11-25 21:43:56 +08:00
parent 723a1ea086
commit 17a43ec181
8 changed files with 1111 additions and 0 deletions
@@ -0,0 +1,159 @@
---
title: "Ein Klick, wieder da Fels in der Brandung: CachedIDAutoJoin und robuste Wiederverbindung in PrivyDrop"
description: "Neu auf der Empfängerseite: AutoBeitritt per zwischengespeicherter ID und durchgängige Wiederverbindung für geschmeidige Abläufe automatischer Raumbeitritt, OneClickConnect, Doppelklick zum CacheUpdate und stabile Erholung in wackeligen Netzen."
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["Neues Feature", "Automatische Wiederverbindung", "Gecachte ID", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## Einleitung: Warum „AutoJoin“ und „Wiederverbindung“ zählen
Neue PrivyDropNutzer stolpern häufig über zwei kleine Reibungen:
- Beim Wechsel von Senden zu Empfangen muss die RaumID erneut eingefügt werden.
- In Café‑WLANs oder im Mobilfunk erzwingt ein kurzer Haker eine manuelle Wiederverbindung.
Klein und doch im Alltag entscheidend dafür, ob sich etwas „mühelos“ anfühlt. Deshalb haben wir zwei Feinschliffe ausgeliefert, die den Fluss wirklich glattziehen:
- „CachedIDAutoJoin“ für Empfänger: Wenn die Bedingungen passen, füllen wir automatisch aus und treten sofort bei.
- Durchgängige, robuste Wiederverbindung: Fällt Socket oder P2P, erholen sich Aushandlung und Verbindung selbsttätig.
Das alles ohne unsere ArchitekturLeitplanke zu verletzen: Backend nur für Signalisierung und Räume; Dateien bleiben E2Everschlüsselt und gehen BrowserzuBrowser direkt.
---
## Funktion 1: AutoJoin mit zwischengespeicherter ID (Empfänger)
Beim Wechsel zum Empfangen füllen wir die letzte gespeicherte RaumID automatisch ein und treten sofort bei, wenn:
- Sie sich im EmpfangenTab befinden und noch keinem Raum beigetreten sind;
- die URL keinen `roomId`Parameter enthält (URL hat Vorrang kein Überschreiben);
- das Eingabefeld leer ist (kein Überschreiben der NutzerEingabe);
- eine gecachte ID in localStorage vorhanden ist.
Der Check läuft beim TabWechsel: Zuerst wird ausgefüllt, dann direkt die Beitrittslogik aufgerufen ein Einfügen/Klick weniger.
- CodeAnker:
- AutoJoin useEffect (Empfänger): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- CacheHelfer (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
Wann greift es nicht?
- Sie sind bereits in einem Raum;
- die URL trägt explizit `roomId` (z.B. geteilter DeepLink);
- das Eingabefeld enthält bereits Text in Bearbeitung;
- keine gecachte ID gefunden.
---
## Funktion 2: „ID speichern/verwenden“ auf SenderSeite (Doppelklick zum Aktualisieren)
Auf der SenderSeite bekommt das IDFeld einen smarten „Wiederverwenden“‑Button mit zwei Zuständen:
- ID speichern: Ab Eingabelänge ≥ 8 wird der Button aktiv; Klick speichert die aktuelle Eingabe als CacheID.
- Gecachte ID verwenden: Existiert eine, schreibt ein Klick sie ins Feld und tritt sofort bei; Doppelklick schaltet ~3s auf „ID speichern“, um den Cache zu erneuern.
Implementierungsnotizen:
- Einfach/Doppelklick via 400msFenster und Timer, Cleanup beim Unmount;
- Nach „Gecachte ID verwenden“ tritt der Sender sofort dem Raum bei (kein zusätzlicher „Beitreten“‑Klick);
- IDs mit weniger als 8 Zeichen werden nicht gespeichert Schutz vor versehentlichen KurzIDs.
- CodeAnker:
- Einfach/Doppelklick inkl. TimerCleanup: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Sofortiger Beitritt bei „Gecachte ID verwenden“ (Sender): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## Wiederverbindung: Von der Erkennung bis zur Erholung
Wir beobachten drei Einstiegspunkte und stoßen die Wiederverbindung an:
- Socket getrennt: Nach Reconnect und geändertem `socketId` erfolgt der automatische RaumBeitritt;
- P2P getrennt/fehlgeschlagen/geschlossen: Status markieren und Verbindung neu aufbauen;
- Proaktiver `socketId`Check: Bei SocketRecovery erneut validieren.
- CodeAnker:
- AutoBeitritt nach SocketConnect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Vereinheitlichter attemptReconnectionEinstieg: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` verfolgen und bei Bedarf `initiator-online`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Sender verarbeitet `recipient-ready` und startet Neuverhandlung: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Empfänger antwortet auf `initiator-online` mit `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- BackendRelais:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### Sequenz (Mermaid)
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as Sender (initiator)
participant B as Empfänger (recipient)
Note over A,B: Netzschwankungen trennen Socket/P2P
A->>A: attemptReconnection()
A->>S: join(roomId) / (ggf.) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: Verbindung wiederhergestellt, DataChannel neu aufgebaut
```
### Zuverlässigkeitsdetails
- ICEKandidatenQueue: Ist die RemoteDescription nicht bereit oder die Verbindung im Schließen, werden Kandidaten gepuffert und später geflusht; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannelBackpressure & Chunking: SenderSchwelle `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); Netzsteuerung `maxBuffer≈3MB / lowThreshold≈512KB / 64KBChunks` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- Mobile Wake Lock: Beim Verbinden anfordern, bei Trennung/Fehler freigeben reduziert Unterbrechungen im Hintergrund.
- Fehlerkapselung & Retries: seltene `sendData failed` werden gekapselt, angezeigt und erneut versucht (siehe `sendWithBackpressure`).
### Kurze vs. lange IDs: Wiederverwendungsstrategie
- Kurze IDs (4stellig) erhalten nach „leerem Raum + Trennung“ eine GnadenTTL von 15Min. (900s) schnelle Wiederverbindung im Fenster; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- StandardAblaufzeit für Räume: 24h; nur bei leerem Raum nach Trennung wird temporär auf 15Min. umgestellt; siehe https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- Lange IDs (UUIDartig) eignen sich für Wiederverwendung über Sitzungen/Geräte hinweg am besten mit dem CacheButton kombinieren.
---
## Ausprobieren (Handson)
Schnelltest am Desktop:
1. Auf SenderSeite eine benutzerdefinierte ID (≥ 8 Zeichen) eingeben und „ID speichern“ klicken.
2. Zum Empfänger wechseln: Wenn die Bedingungen passen, wird automatisch ausgefüllt und beigetreten.
3. Ausfall simulieren (WLAN aus, Hotspot an, refresh & zurück) und die AutoWiederverbindung beobachten.
4. Auf SenderSeite „Gecachte ID verwenden“ doppelklicken, kurzzeitig auf „ID speichern“ umschalten und auf eine neue lange ID aktualisieren.
Mobil/Problemnetze:
- Hintergrund → Vordergrund; Wechsel WLAN ↔ Mobilfunk.
- Prüfen, ob der Empfänger autobeitritt und die Übertragung nahtlos fortsetzt.
---
## Schluss & Aufruf
Je geschmeidiger die Verbindung, desto größer der P2PWert. CachedIDAutoJoin und robuste Wiederverbindung machen PrivyDrop im echten Netz noch verlässlicher.
Wenn Ihnen das gefällt, freuen wir uns über einen Stern auf GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>). Das hilft, entdeckt zu werden und treibt uns an, weiter zu feilen.
Jetzt online testen: <u>https://www.privydrop.app</u>. Feedback und Verbesserungsvorschläge gern als Issue helfen Sie uns, das „glatte Gefühl“ weiter auszubauen.
Zusätzlich sorgt Cloudflare CDN für Beschleunigung über Regionen hinweg schnellere, stabilere Zugriffe, weniger Ruckler.
Weiterführende Lektüre:
- [Warum ich PrivyDrop Open Source gestellt habe](/blog/privydrop-open-source)
- [Wie WebRTC BrowserDirekttransfer ermöglicht](/blog/webRTC-file-transfer)
- [Resumable Transfers: Schluss mit der GroßdateiAnxiety](/blog/resumable-transfers)
@@ -0,0 +1,159 @@
---
title: "OneClick Reconnect, RockSolid: A Deep Dive into CachedID AutoJoin and Resilient Reconnect in PrivyDrop"
description: "New on the receiver: cachedID autojoin and fullpath reconnect for smoother flows — auto room join, onetap direct connect, doubletap to update the cache, and steady recovery on flaky networks."
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["New Feature", "Auto Reconnect", "Cached ID", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## Introduction: Why “AutoJoin” and “Reconnect” Matter
New users of PrivyDrop often run into two tiny frictions:
- When switching from Sender to Receiver, you have to paste the room ID again.
- On café WiFi or mobile data, a brief blip means a manual reconnect.
Tiny? Yes. Frequent in realworld networks? Absolutely. And they decide whether an app feels “effortless.” So we shipped two polishlevel upgrades that make the flow truly smooth:
- Receiver “CachedID AutoJoin”: when conditions match, we autofill and join the room for you.
- Endtoend “Resilient Reconnect”: whether Socket or P2P drops, negotiation and connection recover on their own.
Most importantly, none of this changes our redline architecture: the backend only handles signaling and room management; files are always endtoend encrypted and go directly browsertobrowser.
---
## Feature 1: Receiver CachedID AutoJoin
When you switch to the Receiver tab, if the following conditions are met, the last cached room ID will be autofilled and the app will immediately join the room:
- Youre on the Receiver tab and not already in a room;
- The URL has no explicit `roomId` param (URL wins — we dont override);
- The input is currently empty (we dont override your typing);
- A cached ID exists in localStorage.
This logic triggers on tab switch. If matched, we first fill the input, then immediately call the join routine—one less paste/click.
- Code anchors:
- Receiverside autojoin useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Cache helper (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
When will it not trigger?
- Youre already in a room;
- The URL explicitly carries a `roomId` (e.g., a shared deep link);
- Theres already text in the input that youre editing;
- No cached ID is found.
---
## Feature 2: Sender “Save/Use Cached ID” (DoubleTap to Update)
On the Sender side, the room ID field gets a smart “Reuse” button that toggles between two states:
- Save ID: when the input length is ≥ 8, the button becomes active; clicking saves the current input as the cached ID.
- Use Cached ID: if a cached ID exists, a single tap writes it into the input and joins immediately; a doubletap flips the button to “Save ID” for about 3 seconds so you can refresh the cache.
Implementation notes:
- Single/double taps use a 400ms window with a timer thats cleaned up on unmount;
- After “Use Cached ID” is clicked, the Sender joins the room immediately (no extra “Join” click);
- We dont allow saving IDs shorter than 8 chars to avoid accidental short saves.
- Code anchors:
- Single/doubletap with timer cleanup: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Autojoin immediately on “Use Cached ID” (Sender): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## Reconnect: From Detection to Full Recovery
We watch for disconnects from three entry points and trigger reconnection:
- Socket disconnected: after reconnecting, if `socketId` changes, we auto rejoin the room;
- P2P disconnected/failed/closed: we flag state and attempt to rebuild the connection;
- Proactive `socketId` change check: on socket recovery, we validate once more.
- Code anchors:
- Auto rejoin after socket connects: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Unified attemptReconnection entry: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Track `lastJoinedSocketId` and trigger `initiator-online` when needed: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Sender handles `recipient-ready` and restarts negotiation: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Receiver responds to `initiator-online` with `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Backend signaling relay:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### Sequence (Mermaid)
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as Sender (initiator)
participant B as Receiver (recipient)
Note over A,B: Network blips cause Socket/P2P disconnects
A->>A: attemptReconnection()
A->>S: join(roomId) / (maybe) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: Connection restored, DataChannel re-established
```
### Reliability Details
- ICE candidate queue: if the remote description isnt ready or the connection is closing/closed, candidates are queued and flushed later; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannel backpressure & chunking: Sender threshold `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); network control `maxBuffer≈3MB / lowThreshold≈512KB / 64KB chunks` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- Mobile wake lock: request Wake Lock when connected; release on disconnect/failure to reduce background interruptions.
- Error wrapping & retries: rare `sendData failed` paths are wrapped, surfaced, and retried (see `sendWithBackpressure`).
### Short vs Long IDs: Reuse Strategy
- Short IDs (4digit) get a 15minute (900s) grace TTL when a room becomes empty after a disconnect—allowing quick reconnection within the window; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- Default room expiry is 24 hours; only emptyroom disconnects switch to the temporary 15minute keepalive; see https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- Long IDs (UUIDlike) are better for crosssession/crossdevice reuse; pair them with the cachedID button for best ergonomics.
---
## Try It (HandsOn)
Desktop quick try:
1. On the Sender, enter a custom ID with ≥ 8 characters and click “Save ID”.
2. Switch to the Receiver: if conditions match, it autofills and joins the room.
3. Simulate a dropout (turn WiFi off, switch to hotspot, refresh and return) and watch it reconnect automatically.
4. On the Sender, doubletap “Use Cached ID” to temporarily switch to “Save ID” and update to a new long ID.
Mobile/poor network scenarios:
- Background → foreground; switch WiFi ↔ cellular.
- Observe whether the Receiver autojoins, and whether transfer resumes automatically.
---
## WrapUp & Call to Action
Smoother connections amplify the value of P2P. CachedID autojoin on the receiver and resilient reconnect across the stack make PrivyDrop sturdier and more dependable in the real world.
If you find this useful, please star us on GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) so more people can discover it. Your star directly affects search and recommendation signals—and fuels our motivation to keep polishing.
Try it online: <u>https://www.privydrop.app</u>. We also welcome issues with your feedback and suggestions—help us make the “smooth experience” even smoother.
Additionally, our domain is accelerated via Cloudflare CDN (saintly cyber help), significantly improving crossregion speed and stability so more users can open the site without hiccups.
Further Reading:
- [Why I OpenSourced PrivyDrop](/blog/privydrop-open-source)
- [How WebRTC Enables BrowserDirect Transfer](/blog/webRTC-file-transfer)
- [Resumable Transfers: Say Goodbye to BigFile Anxiety](/blog/resumable-transfers)
@@ -0,0 +1,159 @@
---
title: "Un toque y de vuelta, sólido como roca: Autounión por ID en caché y reconexión resiliente en PrivyDrop"
description: "Novedad en el receptor: autoentrada mediante ID en caché y reconexión de extremo a extremo para un flujo más suave — entrada automática, conexión directa con un toque, doble toque para actualizar la caché y recuperación firme en redes inestables."
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["Nueva función", "Reconexión automática", "ID en caché", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## Introducción: por qué importan el “autojoin” y la “reconexión”
Quien prueba PrivyDrop por primera vez tropieza con dos fricciones pequeñas pero frecuentes:
- Al pasar de Enviar a Recibir, hay que pegar de nuevo el ID de sala.
- En WiFi de cafetería o datos móviles, un microcorte obliga a reconectar manualmente.
Pequeñeces, sí. Pero en red real aparecen mucho y deciden si algo se siente “sin esfuerzo”. Por eso lanzamos dos mejoras de acabado que pulen el flujo hasta hacerlo realmente suave:
- “Autounión por ID en caché” en el receptor: si se cumplen las condiciones, rellenamos y entramos en la sala automáticamente.
- “Reconexion resiliente” de extremo a extremo: caiga Socket o P2P, la negociación y la conexión se recuperan solas.
Y lo más importante: no tocamos nuestra línea roja arquitectónica. El backend solo hace señalización y salas; los archivos siempre viajan de navegador a navegador con cifrado de extremo a extremo.
---
## Función 1: Autounión del receptor con ID en caché
Al cambiar a la pestaña de Receptor, si se cumplen estas condiciones, rellenamos el último ID de sala guardado y entramos al instante:
- Estás en la pestaña de Recibir y aún no estás en una sala;
- La URL no incluye `roomId` (la URL manda; no sobrescribimos);
- El campo de entrada está vacío (no pisamos lo que escribes);
- Existe un ID en caché en localStorage.
La lógica se dispara al cambiar de pestaña: primero rellenamos, luego llamamos directamente a unirse—un pegado/clic menos.
- Anclas de código:
- useEffect de autoentrada en el receptor: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Utilidad de caché (localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
¿Cuándo no se activa?
- Ya estás dentro de una sala;
- La URL trae `roomId` explícito (por ejemplo, enlace compartido con parámetro);
- El campo de entrada ya contiene texto en edición;
- No hay ID en caché.
---
## Función 2: “Guardar/Usar ID en caché” en el emisor (doble toque para actualizar)
En el lado Emisor, el campo del ID incorpora un botón inteligente de “Reusar” con dos estados:
- Guardar ID: con longitud ≥ 8, el botón se habilita; al pulsar, guarda el texto actual como ID en caché.
- Usar ID en caché: si existe, un toque lo escribe en el campo y se une de inmediato; con doble toque, el botón pasa durante ~3 s a “Guardar ID” para que puedas actualizar la caché.
Notas de implementación:
- El simple/doble toque se decide en una ventana de 400 ms con temporizador, limpiado al desmontar;
- Tras “Usar ID en caché”, el emisor entra a la sala inmediatamente (sin pulsar “Unirse”);
- No permitimos guardar IDs de menos de 8 caracteres para evitar guardados accidentales.
- Anclas de código:
- Simple/doble toque y limpieza del temporizador: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Unión inmediata al “Usar ID en caché” (emisor): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## Reconexión: de la detección a la recuperación completa
Observamos tres puntos para detectar cortes y disparar la reconexión:
- Socket desconectado: si al volver cambia el `socketId`, reentramos a la sala automáticamente;
- P2P desconectado/fallido/cerrado: marcamos estado e intentamos reconstruir la conexión;
- Comprobación proactiva de cambio de `socketId`: al recuperar el socket, validamos de nuevo.
- Anclas de código:
- Reentrada automática tras reconectar el socket: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Punto unificado de attemptReconnection: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Registro de `lastJoinedSocketId` y envío de `initiator-online` si procede: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- El emisor recibe `recipient-ready` y reinicia la negociación: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- El receptor responde a `initiator-online` con `recipient-ready`: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Relé de señalización en backend:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### Secuencia (Mermaid)
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as Emisor (initiator)
participant B as Receptor (recipient)
Note over A,B: Microcortes provocan desconexión de Socket/P2P
A->>A: attemptReconnection()
A->>S: join(roomId) / (quizá) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: Conexión restaurada, DataChannel restablecido
```
### Detalles de fiabilidad
- Cola de candidatos ICE: si la descripción remota no está lista o la conexión se cierra, los candidatos se encolan y se envían después; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- Backpressure y troceado del DataChannel: umbral del emisor `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); control de red `maxBuffer≈3MB / lowThreshold≈512KB / trozos de 64KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- Wake Lock móvil: se solicita al conectar y se libera al desconectar/fallar, para reducir interrupciones al pasar a segundo plano.
- Envoltorio de errores y reintentos: los raros `sendData failed` se capturan, se muestran y se reintentan (ver `sendWithBackpressure`).
### Estrategia de reutilización: IDs cortos vs largos
- IDs cortos (4 dígitos) reciben un TTL de 15 minutos (900s) cuando la sala queda vacía tras la desconexión; permite reconectar fácilmente en esa ventana; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- La expiración por defecto de la sala es 24 horas; solo en “sala vacía + desconexión” pasamos a la retención temporal de 15 minutos; ver https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- IDs largos (tipo UUID) son mejores para reutilización entre sesiones/dispositivos; combínalos con el botón de caché para la mejor ergonomía.
---
## Cómo probarlo (handson)
Prueba rápida en escritorio:
1. En el Emisor, escribe un ID personalizado de ≥ 8 caracteres y pulsa “Guardar ID”.
2. Cambia al Receptor: si se cumplen condiciones, se rellenará y entrará automáticamente.
3. Simula un corte (apaga el WiFi, cambia a hotspot, recarga y vuelve) y observa la reconexión automática.
4. En el Emisor, haz doble toque en “Usar ID en caché” para cambiar temporalmente a “Guardar ID” y actualizar a un ID largo nuevo.
Móvil/redes pobres:
- Segundo plano → primer plano; cambia entre WiFi ↔ datos.
- Observa si el receptor se autoune y si la transferencia se reanuda sola.
---
## Cierre y llamada a la acción
Cuanto más suave es la conexión, más crece el valor del P2P. El autojoin por ID en caché y la reconexión resiliente hacen que PrivyDrop sea más robusto y confiable en redes reales.
Si te resulta útil, déjanos una estrella en GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) para que más personas nos encuentren. Tu estrella impacta en búsqueda y recomendaciones—y alimenta nuestras ganas de seguir puliendo.
Pruébalo online: <u>https://www.privydrop.app</u>. También te invitamos a abrir issues con comentarios y sugerencias para seguir afinando esa “experiencia sin fricción”.
Además, el dominio está acelerado con Cloudflare CDN, mejorando notablemente velocidad y estabilidad entre regiones para una apertura sin tirones.
Lecturas recomendadas:
- [Por qué hice PrivyDrop de código abierto](/blog/privydrop-open-source)
- [Cómo WebRTC permite la transferencia directa entre navegadores](/blog/webRTC-file-transfer)
- [Transferencias reanudables: adiós a la ansiedad por los archivos grandes](/blog/resumable-transfers)
@@ -0,0 +1,158 @@
---
title: "Un clic et ça repart, solide comme un roc : Autojoin via ID en cache et reconnexion résiliente dans PrivyDrop"
description: "Nouveauté côté réception : autoentrée grâce à lID en cache et reconnexion de bout en bout pour un flux plus fluide — entrée automatique, connexion directe en un clic, doubleclic pour mettre à jour le cache, et reprise fiable sur réseau instable."
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["Nouvelle fonctionnalité", "Reconnexion automatique", "ID en cache", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## Introduction : pourquoi « autojoin » et « reconnexion »
Les nouveaux utilisateurs de PrivyDrop rencontrent souvent deux petites frictions :
- En passant dEnvoyer à Recevoir, il faut recoller lID de salle ;
- Sur un WiFi de café ou en 4G, une microcoupure impose une reconnexion manuelle.
Des détails ? Oui. Mais très fréquents dans le monde réel — ils font la différence entre « ça marche » et « cest fluide ». Nous avons donc livré deux finitions qui rendent lexpérience vraiment soyeuse :
- « Autojoin via ID en cache » côté récepteur : si les conditions sont réunies, on pré‑remplit et on rejoint la salle automatiquement ;
- « Reconnexion résiliente » de bout en bout : que Socket ou P2P tombe, la négociation et la connexion se rétablissent seules.
Le tout sans toucher à notre ligne rouge architecturale : le backend ne fait que la signalisation et la gestion de salle ; les fichiers restent chiffrés de bout en bout, directement de navigateur à navigateur.
---
## Fonction 1 : Autojoin du récepteur avec ID en cache
Lorsque vous passez à longlet Récepteur, si les conditions suivantes sont réunies, le dernier ID de salle en cache est pré‑rempli et lentrée est immédiate :
- Vous êtes sur longlet Récepteur et pas encore dans une salle ;
- LURL ne contient pas `roomId` (lURL lemporte — pas d’écrasement) ;
- Le champ de saisie est vide (on ne remplace pas votre saisie) ;
- Un ID en cache existe dans le localStorage.
La logique se déclenche au changement donglet. Si cest bon, on remplit dabord, puis on appelle aussitôt la routine dentrée — un collage/clic de moins.
- Repères de code :
- useEffect dautoentrée côté récepteur : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- Utilitaire de cache (localStorage) : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
Quand cela ne sappliquetil pas ?
- Vous êtes déjà dans une salle ;
- LURL porte explicitement `roomId` (lien de partage avec paramètre) ;
- Le champ contient déjà un texte en cours de saisie ;
- Aucun ID en cache nest trouvé.
---
## Fonction 2 : « Enregistrer / Utiliser lID en cache » côté émetteur (doubleclic pour mettre à jour)
Sur l’émetteur, le champ dID accueille un bouton « Réutiliser » astucieux qui alterne entre deux états :
- Enregistrer lID : quand la longueur ≥ 8, le bouton sactive ; un clic enregistre la saisie courante comme ID en cache.
- Utiliser lID en cache : sil existe, un clic linsère et rejoint la salle immédiatement ; un doubleclic bascule ~3 s en « Enregistrer lID » pour actualiser le cache.
Notes dimplémentation :
- Simple/doubleclic via une fenêtre de 400 ms, timer nettoyé au démontage ;
- Après « Utiliser lID en cache », l’émetteur rejoint la salle immédiatement (pas de clic « Rejoindre » supplémentaire) ;
- Pas denregistrement dID de moins de 8 caractères pour éviter les « courts » accidentels.
- Repères de code :
- Simple/doubleclic et nettoyage du timer : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- Rejoindre immédiatement après « Utiliser lID en cache » (émetteur) : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## Reconnexion : de la détection au rétablissement complet
Nous surveillons trois points dentrée et déclenchons la reconnexion :
- Socket déconnecté : après reconnexion, si le `socketId` change, on ré‑entre automatiquement ;
- P2P déconnecté/échec/fermé : on marque l’état et on tente de reconstruire la connexion ;
- Vérification proactive de changement de `socketId` : à la reprise du socket, on revalide.
- Repères de code :
- Ré‑entrée auto après connexion du socket : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- Point dentrée unifié attemptReconnection : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- Suivi de `lastJoinedSocketId` et émission de `initiator-online` si nécessaire : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- Côté émetteur, réception de `recipient-ready` et reprise de la négociation : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- Côté récepteur, réponse `recipient-ready` à `initiator-online` : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- Relais côté backend :
- ready : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected : https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### Séquence (Mermaid)
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as Émetteur (initiator)
participant B as Récepteur (recipient)
Note over A,B: Les aléas réseau coupent Socket/P2P
A->>A: attemptReconnection()
A->>S: join(roomId) / (évent.) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: Connexion restaurée, DataChannel ré‑établi
```
### Détails de fiabilité
- File dattente des candidats ICE : si la description distante nest pas prête ou que la connexion se ferme, on met en file et on rejoue plus tard ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- Rétropression et découpage DataChannel : seuil émetteur `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82) ; contrôle réseau `maxBuffer≈3MB / lowThreshold≈512KB / chunks de 64KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- Wake Lock mobile : demande à l’établissement de la connexion, libération à la déconnexion/échec — pour réduire les interruptions en arrièreplan.
- Encapsulation derreurs et retries : les rares `sendData failed` sont capturés, surfacés et réessayés (voir `sendWithBackpressure`).
### Stratégie de réutilisation : IDs courts vs longs
- IDs courts (4 chiffres) : en cas de « salle vide + déconnexion », TTL de grâce de 15 minutes (900s) — reconnexion rapide dans la fenêtre ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- Expiration par défaut : 24 h ; seul le cas « salle vide + déconnexion » passe en conservation temporaire de 15 min ; voir https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- IDs longs (type UUID) : mieux pour la réutilisation intersessions/appareils ; les combiner avec le bouton dID en cache offre la meilleure ergonomie.
---
## Prise en main (handson)
Essai rapide sur desktop :
1. Côté Émetteur, entrez un ID personnalisé (≥ 8 caractères) et cliquez « Enregistrer lID ».
2. Passez au Récepteur : si les conditions sont réunies, autoremplissage et entrée immédiate.
3. Simulez une coupure (coupure WiFi, bascule hotspot, actualiser puis revenir) et observez la reconnexion automatique.
4. Côté Émetteur, doublecliquez « Utiliser lID en cache » pour basculer brièvement en « Enregistrer lID » et mettre à jour vers un nouvel ID long.
Mobile / réseaux difficiles :
- Arrièreplan → premier plan ; bascule WiFi ↔ cellulaire.
- Vérifiez lautoentrée du Récepteur et la reprise automatique du transfert.
---
## Conclusion & appel à laction
Plus la connexion est fluide, plus la valeur du P2P grandit. Lautojoin via ID en cache et la reconnexion résiliente renforcent la robustesse de PrivyDrop dans les réseaux réels.
Si vous aimez, metteznous une étoile sur GitHub (<u>https://github.com/david-bai00/PrivyDrop</u>) — cela accroît la visibilité et nourrit notre envie de peaufiner.
Essai en ligne : <u>https://www.privydrop.app</u>. Vos retours et idées sont bienvenus via les issues : continuons ensemble à polir « lexpérience soyeuse ».
Par ailleurs, notre domaine bénéficie de laccélération Cloudflare CDN, améliorant nettement vitesse et stabilité interrégions.
Pour aller plus loin :
- [Pourquoi jai opensourcé PrivyDrop](/blog/privydrop-open-source)
- [Comment WebRTC permet le transfert direct entre navigateurs](/blog/webRTC-file-transfer)
- [Transferts reprenables : adieu à lanxiété des gros fichiers](/blog/resumable-transfers)
@@ -0,0 +1,159 @@
---
title: "ワンタップで復帰、盤石の安定性:PrivyDrop のキャッシュID自動参加と切断時の再接続を徹底解説"
description: "受信側のキャッシュID自動入室と全経路の自動再接続で、体験はより滑らかに。自動入室、ワンタップ直結、ダブルタップでキャッシュ更新、そして不安定なネットでも粘り強く復帰します。"
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["新機能", "自動再接続", "キャッシュID", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## はじめに:なぜ「自動入室」と「再接続」なのか
PrivyDrop を初めて使うと、よくある小さな引っかかりが二つあります。
- 送信から受信に切り替えるたび、部屋の ID をもう一度貼り付ける。
- カフェの Wi‑Fi やモバイル回線で一瞬切れると、手動でつなぎ直す。
小さなこと。でも現実のネットワークでは頻出で、使い心地を左右します。そこで私たちは、体験を“するり”と滑らかにする二つの磨き込みを加えました。
- 受信側「キャッシュIDの自動入室」:条件を満たせば、自動で入力&即入室。
-, エンドツーエンドの「粘り強い再接続」:Socket / P2P のどちらが落ちても、自動で再ネゴシエーション&復旧。
そして大切なのは、アーキテクチャのレッドラインは不変であること。バックエンドは信令とルーム管理のみ、ファイルは常に E2E 暗号化でブラウザ間を直送します。
---
## 機能1:受信側のキャッシュID自動入室
受信タブへ切り替えた際、以下の条件を満たすと、最後に保存した部屋 ID を自動入力し、すぐ入室します。
- 受信タブにいて、まだ入室していない;
- URL に `roomId` パラメータがない(URL が優先、上書きしない);
- 入力欄が空(ユーザーの入力は上書きしない);
- localStorage にキャッシュ ID が存在する。
この判定はタブ切り替え時に走ります。条件一致なら、入力欄を埋めてからそのまま入室ロジックを呼び出し、貼り付け/クリックを 1 回減らします。
- コード参照:
- 受信側の自動入室 useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- キャッシュユーティリティ(localStorage: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
発動しないとき:
- すでに入室している;
- URL が明示的に `roomId` を持つ(共有リンクなど);
- 入力欄に既に文字があり編集中;
- キャッシュ ID が存在しない。
---
## 機能2:送信側の「保存/使用」ボタン(ダブルタップで更新)
送信側の部屋 ID 入力欄に、賢い「再利用」ボタンを追加しました。状態は 2 つに切り替わります。
- ID を保存:入力長が 8 文字以上で有効化。クリックで現在の入力をキャッシュ ID として保存。
- キャッシュ ID を使用:キャッシュがあれば、ワンタップで入力欄に反映してそのまま入室。ダブルタップすると約 3 秒だけ「ID を保存」に切り替わり、キャッシュを更新できます。
実装メモ:
- シングル/ダブルタップは 400ms の判定窓+タイマーで実現し、アンマウント時にクリーンアップ;
- 「キャッシュ ID を使用」後は送信側が即入室(追加の「入室」操作は不要);
- 8 文字未満は保存不可にして、短い ID の誤保存を防止。
- コード参照:
- シングル/ダブルタップとタイマーのクリーンアップ: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- 「キャッシュ ID を使用」で即入室(送信側): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## 再接続:検知から復旧までの流れ
私たちは 3 つの入口から「切断」を監視し、再接続を走らせます。
- Socket 切断:再接続後に `socketId` が変わっていれば自動再入室;
- P2P 切断/失敗/クローズ:状態をマーキングし、接続再構築を試行;
- `socketId` の変化を能動チェック:Socket 復旧時に再確認。
- コード参照:
- Socket 接続後の自動再入室: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- 再接続の統一エントリ: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` の記録と必要時の `initiator-online` 送出: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- 送信側の `recipient-ready` 受信と再ネゴシエーション開始: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- 受信側の `initiator-online` 受信と `recipient-ready` 応答: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- バックエンドの信令リレー:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### シーケンス(Mermaid
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as 送信側(initiator)
participant B as 受信側(recipient)
Note over A,B: ネットの揺らぎで Socket/P2P が切断
A->>A: attemptReconnection()
A->>S: join(roomId) / (場合により)initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: 接続回復、DataChannel 再確立
```
### 信頼性ディテール
- ICE 候補キュー:リモート記述が未確立、または接続がクローズ系なら候補をキューイングし、後でまとめて反映;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256。
- DataChannel の背圧と分割送信:送信側しきい値 `bufferedAmountLowThreshold=256KB`https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82);ネットワーク制御は `maxBuffer≈3MB / lowThreshold≈512KB / 64KB チャンク`https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210)。
- モバイルの Wake Lock:接続時に取得、切断/失敗で解放。バックグラウンド遷移による中断を低減。
- エラー包みとリトライ:まれな `sendData failed` を捕捉し、表面化&再試行(`sendWithBackpressure` を参照)。
### 短い ID と長い ID の使い分け
- 短い ID(4 桁)は「空室で切断」時、バックエンドが 15 分(900s)の TTL に更新。猶予内は再接続が容易;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125。
- 既定の部屋期限は 24 時間。空室切断のときのみ 15 分の一時保持に切替;https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6。
- 長い ID(UUID 相当)はセッション横断・デバイス横断の再利用に向く。キャッシュ ID ボタンと組み合わせると最良。
---
## 触ってみる(クイックスタート)
デスクトップでの手早い体験:
1. 送信側で 8 文字以上の任意 ID を入力し、「ID を保存」をクリック。
2. 受信側へ切り替え:条件を満たせば自動入力&即入室。
3. 切断を再現(Wi‑Fi を切る、テザリングへ切替、リロード→戻る)して、自動復帰を観察。
4. 送信側で「キャッシュ ID を使用」をダブルタップし、一時的に「ID を保存」に切替→新しい長い ID へ更新。
モバイル/弱い回線の場面:
- バックグラウンド→フォアグラウンド、Wi‑Fi とセルラーの切替。
- 受信側の自動入室や、転送の自動再開を確認。
---
## 結びとお願い
“するり”とつながるほど、P2P の価値は増幅します。受信側のキャッシュ ID 自動入室と、スタック全体の再接続により、PrivyDrop は現実のネット環境でいっそう頑丈で頼れる存在になりました。
もし気に入っていただけたら、ぜひ GitHub で Star をお願いします(<u>https://github.com/david-bai00/PrivyDrop</u>)。見つけてもらいやすくなるだけでなく、私たちの磨き込みの原動力にもなります。
オンライン体験:<u>https://www.privydrop.app</u>。Issue から体験フィードバックや改善提案も歓迎します。“なめらかな体験”を、さらに厚くしていきましょう。
なお、ドメインは Cloudflare CDN による加速を有効化。地域間の速度と安定性が向上し、より多くのユーザーがストレスなくアクセスできます。
関連記事:
- [なぜ PrivyDrop をオープンソース化したのか](/blog/privydrop-open-source)
- [WebRTC はどうやってブラウザ直送を実現するのか](/blog/webRTC-file-transfer)
- [レジューム転送:大容量でも焦らない](/blog/resumable-transfers)
@@ -0,0 +1,159 @@
---
title: "원탭 재연결, 바위처럼 단단하게: PrivyDrop의 캐시 ID 자동 입장과 탄탄한 재연결 완전 해부"
description: "받는 쪽 캐시 ID 자동 입장과 전 구간 재연결로 흐름이 더 매끄럽게—자동 입장, 한 번 탭으로 즉시 연결, 두 번 탭으로 캐시 갱신, 불안정한 네트워크에서도 끈질긴 복구."
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: ["신기능", "자동 재연결", "캐시된 ID", "WebRTC", "P2P"]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## 소개: 왜 “자동 입장”과 “재연결”인가
PrivyDrop을 처음 쓰면 자주 마주치는 두 가지 작은 마찰이 있습니다.
- 발신 → 수신으로 바꿀 때마다 방 ID를 다시 붙여넣어야 함
- 카페 Wi‑Fi나 모바일 네트워크에서 잠깐 끊기면 직접 다시 연결해야 함
작지만, 현실 네트워크에서는 자주 일어납니다. 그리고 “손맛”을 좌우합니다. 그래서 흐름을 정말 부드럽게 만드는 두 가지 개선을 넣었습니다.
- 수신 측 “캐시 ID 자동 입장”: 조건이 맞으면 자동으로 입력하고 곧바로 입장
- 전체 경로 “탄탄한 재연결”: Socket/P2P 어느 쪽이 끊겨도 스스로 재협상/복구
무엇보다 우리의 아키텍처 레드라인은 그대로입니다. 백엔드는 신호와 방 관리만 담당하고, 파일은 E2E로 암호화된 상태로 브라우저끼리 직접 전송됩니다.
---
## 기능 1: 수신 측 캐시 ID 자동 입장
수신 탭으로 전환했을 때 아래 조건을 만족하면, 마지막으로 저장된 방 ID를 자동으로 채우고 즉시 입장합니다.
- 현재 수신 탭이고 아직 방에 들어가지 않았음
- URL에 `roomId` 파라미터가 없음(주소가 우선, 덮어쓰지 않음)
- 입력 칸이 비어 있음(사용자 입력을 덮어쓰지 않음)
- localStorage에 캐시 ID가 존재함
이 로직은 탭 전환 때 트리거됩니다. 조건이 맞으면 입력 칸을 채운 뒤 바로 입장 로직을 호출하여, 붙여넣기/클릭을 한 번 줄입니다.
- 코드 앵커:
- 수신 측 자동 입장 useEffect: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151
- 캐시 유틸(localStorage): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1
다음 상황에서는 동작하지 않습니다.
- 이미 방에 들어가 있음
- URL에 `roomId`가 명시됨(공유 링크 등)
- 입력 칸에 이미 텍스트가 있고 편집 중임
- 캐시 ID가 없음
---
## 기능 2: 발신 측 “저장/사용” 버튼(더블 탭으로 업데이트)
발신 측 방 ID 입력란에 똑똑한 “재사용” 버튼을 추가했습니다. 두 가지 상태를 오갑니다.
- ID 저장: 입력 길이가 8자 이상이면 활성화. 클릭 시 현재 입력을 캐시 ID로 저장
- 캐시 ID 사용: 캐시가 있으면 한 번 탭으로 입력란에 채우고 곧바로 입장. 두 번 탭하면 약 3초간 “ID 저장”으로 잠시 전환되어 캐시를 업데이트할 수 있음
구현 노트:
- 단/복 탭은 400ms 윈도우로 판별하며, 컴포넌트 언마운트 시 타이머를 정리
- “캐시 ID 사용” 후에는 발신 측이 즉시 입장(추가 “입장” 클릭 불필요)
- 8자 미만은 저장 불가로 하여, 짧은 ID 오저장을 방지
- 코드 앵커:
- 단/복 탭과 타이머 정리: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112
- “캐시 ID 사용” 시 즉시 입장(발신 측): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193
---
## 재연결: 감지부터 완전 복구까지
세 가지 지점에서 끊김을 감지하고 재연결을 시도합니다.
- Socket 끊김: 재연결 후 `socketId`가 바뀌면 자동 재입장
- P2P 끊김/실패/종료: 상태를 표시하고 연결 재구성을 시도
- `socketId` 변경의 능동 확인: 소켓 복구 시 한 번 더 검증
- 코드 앵커:
- 소켓 연결 후 자동 재입장: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121
- attemptReconnection 통합 진입점: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185
- `lastJoinedSocketId` 기록 및 필요 시 `initiator-online` 트리거: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460
- 발신 측의 `recipient-ready` 처리 및 재협상 시작: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12
- 수신 측의 `initiator-online` 응답(`recipient-ready` 전송): https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14
- 백엔드 신호 릴레이:
- ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63
- initiator-online: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102
- recipient-ready: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108
- peer-disconnected: https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119
### 시퀀스(Mermaid)
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as 발신자(initiator)
participant B as 수신자(recipient)
Note over A,B: 네트워크 흔들림으로 Socket/P2P 끊김
A->>A: attemptReconnection()
A->>S: join(roomId) / (필요 시) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: 연결 복구, DataChannel 재수립
```
### 신뢰성 디테일
- ICE 후보 큐: 원격 설명이 준비되지 않았거나 연결이 종료 단계면 후보를 큐에 담아 두었다가 나중에 한 번에 반영; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256.
- DataChannel 배압과 청킹: 발신 측 임계치 `bufferedAmountLowThreshold=256KB` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82); 네트워크 제어 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 청크` (https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111, https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210).
- 모바일 Wake Lock: 연결 시 획득, 끊김/실패 시 해제 — 백그라운드 전환으로 인한 중단을 줄임.
- 에러 래핑과 재시도: 드물게 발생하는 `sendData failed` 경로를 포착/표면화/재시도(`sendWithBackpressure` 참고).
### 짧은 ID와 긴 ID 재사용 전략
- 짧은 ID(4자리)는 “빈 방 + 끊김” 시 백엔드가 TTL을 15분(900s)으로 갱신 — 그 창에서 빠르게 재연결 가능; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125.
- 기본 방 만료는 24시간; “빈 방 + 끊김”에 한해 일시적으로 15분 보존으로 전환; https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6.
- 긴 ID(UUID 유사)는 세션/디바이스를 넘어 재사용에 유리 — 캐시 ID 버튼과 함께 쓰면 가장 편함.
---
## 바로 써보기 (Handson)
데스크톱 빠른 체험:
1. 발신 측에서 8자 이상 사용자 지정 ID를 입력하고 “ID 저장” 클릭
2. 수신 측으로 전환: 조건이 맞으면 자동 채움 후 즉시 입장
3. 끊김 시나리오 시뮬레이션(Wi‑Fi 끄기, 핫스팟 전환, 새로고침 후 복귀) → 자동 재연결 관찰
4. 발신 측 “캐시 ID 사용” 더블 탭 → 잠시 “ID 저장”으로 전환 → 새 긴 ID로 갱신
모바일/열악한 네트워크:
- 백그라운드 ↔ 포그라운드 전환, Wi‑Fi ↔ 셀룰러 전환
- 수신 측 자동 입장과 전송 자동 복구 동작 확인
---
## 맺음말 & 액션
연결이 매끄러울수록 P2P의 가치는 커집니다. 캐시 ID 자동 입장과 전 구간 재연결로, PrivyDrop은 현실 네트워크에서 더 튼튼하고 믿을 만해졌습니다.
유용했다면 GitHub 별을 부탁드립니다(<u>https://github.com/david-bai00/PrivyDrop</u>). 더 많은 사람이 발견할 수 있고, 저희가 계속 다듬어 가는 동력이 됩니다.
온라인 체험: <u>https://www.privydrop.app</u>. Issue로 사용 소감과 제안을 남겨 주세요. “부드러운 경험”을 더 두텁게 만들어가겠습니다.
덧붙여, 도메인은 Cloudflare CDN 가속을 사용합니다. 지역 간 속도와 안정성이 크게 향상되어, 더 많은 지역에서 끊김 없이 접속할 수 있습니다.
더 읽기:
- [내가 PrivyDrop을 오픈 소스로 공개한 이유](/blog/privydrop-open-source)
- [WebRTC가 브라우저 직결 전송을 구현하는 방법](/blog/webRTC-file-transfer)
- [중단 후 재개 전송: 대용량 전송의 불안을 넘어](/blog/resumable-transfers)
@@ -0,0 +1,158 @@
---
title: "一键复连,稳如磐石:PrivyDrop 接收端缓存ID自动连接与断线重连全解析"
description: "新增接收端缓存ID自动连接与断线重连,让连接更顺滑:自动入房、单击直连、双击更新缓存、弱网稳复连。"
date: "2025-11-25"
author: "david bai"
cover: "/blog-assets/cached-id-reconnect.webp"
tags: [新功能, 断线重连, 缓存ID, WebRTC, P2P]
status: "published"
---
![](/blog-assets/cached-id-reconnect.webp)
## 引言:为什么我们要做“自动入房”和“断线重连”
很多第一次使用 PrivyDrop 的用户,都会经历这样两件“小事”:
- 从发送端切到接收端时,需要再粘贴一次房间 ID;
- 在咖啡店 Wi‑Fi 或移动网络下,短暂断网就要手动重连。
这两件“小事”,在真实世界里却非常高频,也直接决定了“顺不顺手”。为此,我们上线了两项把体验打磨到“顺滑”的改进:
- 接收端“缓存 ID 自动连接”:满足条件时,自动填充并直接入房;
- 全链路“断线重连”:Socket/P2P 任一断开,均自动恢复协商与连接。
更重要的是,这些改进不改变我们的架构红线:后端只做信令与房间管理,文件数据始终端到端加密,浏览器之间直传。
---
## 功能一:接收端缓存 ID 自动连接
当你切换到“接收”面板,如果满足以下条件,将自动填充上次保存的房间 ID 并直接入房:
- 当前处于接收面板,且尚未在房间内;
- URL 未携带 `roomId` 参数(URL 优先,不做覆盖);
- 输入框当前为空(不覆盖用户已有输入);
- 本地存在缓存 IDlocalStorage)。
上述逻辑在切换面板时触发,一旦命中,会先填充输入框,再立即调用加入逻辑,减少一次粘贴/点击。
- 代码锚点:
- 前端自动入房 useEffect(接收端):[frontend/components/ClipboardApp.tsx#L151](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp.tsx#L151)
- 缓存工具(localStorage):[frontend/lib/roomIdCache.ts#L1](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/roomIdCache.ts#L1)
何时不会触发?
- 你已在房间中;
- URL 显式携带了 `roomId`(例如分享链接带参直达);
- 输入框里已有你正在编辑的 ID
- 本地没有缓存 ID。
---
## 功能二:发送端“保存/使用缓存 ID”(支持双击更新)
发送端的房间 ID 输入区新增了一个“复用按钮”,在两种状态间智能切换:
- 保存 ID:当输入长度 ≥ 8 位时按钮可用,点击后将当前输入保存为缓存 ID;
- 使用缓存 ID:若存在缓存 ID,单击即将其写入输入框并立刻入房;双击会“短暂切换”为“保存 ID”,便于你替换更新缓存(约 3 秒后恢复)。
实现要点:
- 单/双击通过 400ms 窗口配合计时器实现,并在组件卸载时清理;
- “使用缓存 ID”单击后,发送端会立即加入房间(无需再点“加入”);
- 输入长度不足 8 位时不会允许保存,避免误存短 ID。
- 代码锚点:
- 单/双击与计时器清理:[frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/CachedIdActionButton.tsx#L112)
- 使用缓存 ID 后立刻直连(发送端):[frontend/components/ClipboardApp/SendTabPanel.tsx#L193](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/components/ClipboardApp/SendTabPanel.tsx#L193)
---
## 断线重连:从检测到恢复的全链路
我们从三个入口观测“断开”并触发重连:
- Socket 断开:重连后若 `socketId` 变化,将自动重新入房;
- P2P 断开/失败/关闭:标记状态并尝试重建连接;
- 主动判断 `socketId` 变化:在 socket 连接恢复时复核一次。
- 代码锚点:
- Socket 连接后自动重入房:[frontend/lib/webrtc_base.ts#L121](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L121)
- 尝试重连的统一入口:[frontend/lib/webrtc_base.ts#L185](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L185)
- 记录 `lastJoinedSocketId` 并在需要时触发 `initiator-online`[frontend/lib/webrtc_base.ts#L460](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L460)
- 发送端接收 `recipient-ready` 并重启协商:[frontend/lib/webrtc_Initiator.ts#L12](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L12)
- 接收端响应 `initiator-online` 并发送 `recipient-ready`[frontend/lib/webrtc_Recipient.ts#L14](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Recipient.ts#L14)
- 后端信令转发:
- ready[backend/src/socket/handlers.ts#L63](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L63)
- initiator-online[backend/src/socket/handlers.ts#L102](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L102)
- recipient-ready[backend/src/socket/handlers.ts#L108](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L108)
- peer-disconnected[backend/src/socket/handlers.ts#L119](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119)
### 时序(Mermaid
```mermaid
sequenceDiagram
participant S as Signaling Server
participant A as 发送端(initiator)
participant B as 接收端(recipient)
Note over A,B: 网络波动导致 Socket/P2P 断开
A->>A: attemptReconnection()
A->>S: join(roomId) / (可能) initiator-online
S-->>B: initiator-online
B->>S: recipient-ready(peerId)
S-->>A: recipient-ready(peerId)
A->>B: offer
B->>A: answer
A-->>B: ICE candidates
B-->>A: ICE candidates
Note over A,B: 连接恢复,DataChannel 重建
```
### 可靠性细节
- ICE 候选队列:若远端描述尚未建立或连接处于关闭态,候选会入队,待可用时批量补交;见 [frontend/lib/webrtc_base.ts#L219-L256](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_base.ts#L219-L256)。
- DataChannel 背压与分片:发送端阈值 `bufferedAmountLowThreshold=256KB`[frontend/lib/webrtc_Initiator.ts#L82](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/webrtc_Initiator.ts#L82));网络发送控制 `maxBuffer≈3MB / lowThreshold≈512KB / 64KB 分片`[frontend/lib/transfer/NetworkTransmitter.ts#L66-L111](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L66-L111)、[frontend/lib/transfer/NetworkTransmitter.ts#L160-L210](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/frontend/lib/transfer/NetworkTransmitter.ts#L160-L210))。
- 移动端唤醒锁:连接建立时申请 Wake Lock,断开/失败时释放,降低切后台导致的意外中断;
- 错误兜底与重试:小概率 `sendData failed` 会被包装、上报与重试(详见 `sendWithBackpressure` 相关逻辑)。
### 短 ID 与长 ID 的复用策略
- 短 ID(4 位)在“空房断开”后,会由后端将房间 TTL 刷新为 15 分钟(900s),窗口期内可直接重连,超时回收;见 [backend/src/socket/handlers.ts#L119-L125](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/socket/handlers.ts#L119-L125)。
- 默认房间过期时间为 24 小时,仅在空房断开发生临时 15 分钟保留;见 [backend/src/services/redis.ts#L6](https://github.com/david-bai00/PrivyDrop/blob/v1.1.1/backend/src/services/redis.ts#L6)。
- 长 ID(如 UUID 级别长度)更适合跨会话、跨设备的持续复用;与缓存 ID 按钮配合使用体验最佳。
---
## 如何体验(上手指南)
桌面端快速体验:
1. 在发送端输入一个 ≥8 位的自定义 ID,点击“保存 ID”;
2. 切换到接收端:若满足条件,将自动填充并直接入房;
3. 模拟断线(如:关闭 Wi‑Fi、切到手机热点、刷新页面再返回),观察自动重连;
4. 在发送端双击“使用缓存 ID”,短暂切换为“保存 ID”,更新为新的长 ID。
移动端/弱网场景:
- 切后台 → 回前台;Wi‑Fi ↔ 蜂窝之间切换;
- 关注接收端是否自动入房、传输是否自动恢复。
---
## 结语与行动号召
我们相信,越“顺手”的连接,越能放大 P2P 的价值。接收端缓存 ID 自动连接与断线重连,让 PrivyDrop 在真实网络环境下更加稳健、可依赖。
如果觉得好用,请到 GitHub 给我们一个 Star<u>https://github.com/david-bai00/PrivyDrop</u>),便于更多人发现与受益;你的 Star 也会直接影响搜索与推荐权重,是我们持续打磨产品的动力。
在线体验:<u>https://www.privydrop.app</u>。也欢迎在 Issue 中反馈你的使用体验与改进建议,让我们把“顺滑体验”继续做厚。
另外,域名已启用 Cloudflare CDN 加速(赛博菩萨),显著提升跨区域的访问速度与稳定性,让更多地区用户打开网站不再卡顿,整体体验更流畅。
延伸阅读:
- [我为什么开源了 PrivyDrop](/blog/privydrop-open-source)
- [WebRTC 如何实现浏览器直传](/blog/webRTC-file-transfer)
- [断点续传:让大文件传输告别焦虑](/blog/resumable-transfers)
Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB