Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ronin P2P

Transfer multi-gigabyte files directly between browsers using WebRTC, without uploading them to a central server.

WebRTC Socket.io React Tailwind CSS License


Technical Overview

Traditional file-sharing services require uploading files to a server before a recipient can download them. This adds transfer delay, wastes server storage, and increases bandwidth costs.

Ronin P2P removes the server from the transfer path by connecting two browsers directly using WebRTC. Files stream straight from sender to receiver, making transfers faster and more privacy-focused.

To handle multi-gigabyte files (such as video masters, database dumps, and zip archives) without crashing the browser, incoming data streams directly to the receiver's disk. Writing data straight to storage instead of keeping it in memory prevents out-of-memory errors during large transfers.


System Architecture & Data Flow Pipeline

Phase 1: Signaling & Connection Handshake

%%{init: {'theme': 'dark', 'themeVariables': { 'fontSize': '16px'}, 'flowchart': {'useMaxWidth': false, 'htmlLabels': true}} }%%
graph TD
    %% Node Stylings
    classDef client fill:#18181b,stroke:#818cf8,stroke-width:2px,color:#fff;
    classDef server fill:#09090b,stroke:#27272a,stroke-width:2px,color:#a1a1aa;
    classDef pipe fill:#1e1b4b,stroke:#6366f1,stroke-width:2px,color:#e0e7ff;

    %% Elements
    Sender["Sender Client (Browser A)"]:::client
    Signaling["Node.js Signaling Server"]:::server
    Receiver["Receiver Client (Browser B)"]:::client
    DataPipe{"Open WebRTC Data Channel"}:::pipe

    %% Step 1: Meeting at the Server
    Sender -->|1. Create Room| Signaling
    Receiver -->|2. Join Room via Link| Signaling

    %% Step 2: Trading Connection Details
    Signaling -->|3. Pass Connection Details| Receiver
    Receiver -->|4. Return Acceptance Details| Signaling
    Signaling -.->|Broker Complete| Sender

    %% Step 3: Going Direct (Cutting out the Middleman)
    Sender ===>|5. Establish Direct P2P Line| DataPipe
    Receiver ===>|5. Establish Direct P2P Line| DataPipe
Loading

Phase 2: High-Velocity Streaming & Asynchronous Backpressure Control

%%{init: {'theme': 'dark', 'themeVariables': { 'fontSize': '16px'}, 'flowchart': {'useMaxWidth': false, 'htmlLabels': true}} }%%
graph TD
    %% Node Stylings
    classDef client fill:#18181b,stroke:#818cf8,stroke-width:2px,color:#fff;
    classDef server fill:#09090b,stroke:#27272a,stroke-width:2px,color:#a1a1aa;
    classDef pipe fill:#1e1b4b,stroke:#6366f1,stroke-width:2px,color:#e0e7ff;
    classDef loop fill:#27272a,stroke:#4b5563,stroke-width:1px,color:#e0e7ff;

    %% Elements
    Sender["Sender Workspace"]:::client
    DataPipe{"Established WebRTC Data Channel"}:::pipe
    Receiver["Receiver Workspace"]:::client
    Disk[(Physical Storage Drive)]:::server

    %% Step 1: File Transfer Handshake
    Sender -->|1. Metadata Header: FILE_REQUEST| DataPipe
    DataPipe -->|2. User Grants Storage Handle: FILE_ACCEPTED| Receiver

    %% Step 2: The Core Backpressure Streaming Engine
    subgraph FlowControl ["Memory Guard: Asynchronous Flow Control Loop"]
        A1[Slice File into 16KB ArrayBuffer Chunks] --> A2{Is dataChannel.bufferedAmount > 2MB?}
        
        %% Congestion Path
        A2 -- YES: Buffer Saturated --> A3[Pause Chunk Reading Loop Thread]
        A3 --> A4[Bind One-Time Hook to onbufferedamountlow]
        A4 --> A5{Has Buffer Dropped Below 1MB?}
        A5 -- YES: Queue Clear --> A6[Wake Thread & Resume Ingestion]
        A6 --> A1
        
        %% Safe Path
        A2 -- NO: Buffer Safe --> A7[dataChannel.send Chunk]
    end

    %% Step 3: Network Transmission & Disk Commits
    Sender -.->|Orchestrates| FlowControl
    A7 -->|3. Push Network Chunks| DataPipe
    DataPipe -->|4. Native FileSystemAccessAPI Stream Write| Receiver
    Receiver -->|5. Zero-Copy Flush| Disk
Loading

Core Engineering Implementations

1. Backpressure Control

During large file transfers, the sender can produce data faster than the network is able to transmit it. If chunks are sent continuously, the WebRTC data channel's internal buffer keeps growing, which increases memory usage and can eventually lead to performance issues or channel errors.

To prevent this, Ronin P2P implements a high and low watermark backpressure mechanism.

Parameter Value Purpose
Chunk Size 16 KB Splits files into manageable chunks for transmission.
High Watermark 2 MB Pause sending when the buffered data exceeds this limit.
Low Watermark 1 MB Resume sending once the buffer drops below this limit.

The sender continuously monitors the data channel's bufferedAmount. When the buffered data exceeds 2 MB, file reading is paused to prevent the buffer from growing further. The application then waits for the onbufferedamountlow event, which is triggered after the buffer falls below 1 MB. Once this event fires, file reading resumes automatically.

This mechanism keeps memory usage stable, prevents buffer overflow, and enables reliable multi-gigabyte file transfers without overwhelming the browser.

2. Direct-to-Disk Streaming

Traditional web applications typically store incoming file data in memory before creating a downloadable file. While this approach works well for smaller files, it becomes inefficient for multi-gigabyte transfers because memory usage continues to grow and may eventually cause the browser tab to crash.

Ronin P2P avoids this by streaming incoming data directly to disk using the File System Access API.

  • Chromium Support: On Chromium-based browsers (Chrome, Edge, Brave), the application requests a writable file handle using window.showSaveFilePicker() before the transfer begins.

  • Direct Disk Writes: Each incoming 16 KB ArrayBuffer chunk is written immediately to a FileSystemWritableFileStream instead of being accumulated in memory. Since data is streamed directly to disk, memory usage remains low regardless of file size.

This allows Ronin P2P to reliably transfer multi-gigabyte files without exhausting the browser's available memory.

3. Performance Optimizations

To keep file transfers responsive and reliable, Ronin P2P includes several runtime optimizations.

Reduced UI Updates

  • Updating React state for every received chunk causes unnecessary re-renders, especially during large file transfers. Instead, Ronin P2P updates the UI only when the transfer percentage changes.

  • This reduces thousands of React renders to at most 100 UI updates per transfer, allowing the browser to spend more time handling network operations instead of rendering the interface.

Wake Lock Support

  • Long file transfers can be interrupted if the operating system puts the device to sleep. On supported browsers, Ronin P2P uses the Screen Wake Lock API (navigator.wakeLock) to keep the screen awake while a transfer is in progress.

  • The wake lock is automatically released when the transfer completes or is cancelled.

Connection Monitoring

  • The application continuously monitors both the WebRTC peer connection and the data channel during a transfer.

  • If the peer connection enters the failed state or the data channel is no longer open, the transfer is stopped immediately. Active file streams are closed, wake locks are released, and application resources are cleaned up to prevent memory leaks.


Browser Compatibility

Ronin P2P uses the File System Access API for direct-to-disk streaming. Since this API is currently supported only by Chromium-based browsers, some features vary by browser.

  • Chromium Browsers (Chrome, Edge, Brave): Full support for direct-to-disk streaming using the File System Access API. Large files can be transferred without consuming significant browser memory.

  • Firefox: Firefox does not currently support the File System Access API. As a fallback, incoming data is temporarily buffered in memory. To avoid excessive memory usage, transfers larger than 200 MB display a recommendation to use a Chromium-based browser for the best experience.


Tech Stack

Frontend

  • React – User interface
  • Vite – Development and build tool
  • Tailwind CSS – Styling
  • Three.js / React Three Fiber – 3D globe visualization

Backend

  • Node.js
  • Socket.io – WebRTC signaling server

Networking

  • WebRTC – Peer-to-peer file transfer
  • STUN / ICE – Peer connection establishment

Browser APIs

  • File System Access API – Direct-to-disk streaming
  • Screen Wake Lock API – Prevents the device from sleeping during transfers

Local Development & Setup

Follow these commands to deploy the project architecture locally:

Prerequisites

Ensure you have Node.js installed on your machine.

Setup Instructions

# 1. Clone the repository structure
git clone [https://github.com/yourusername/roninp2p.git](https://github.com/yourusername/roninp2p.git)

# 2. Access the project root folder
cd roninp2p

# 3. Install core dependencies
npm install

# 4. Initiate the localized dev workspace
npm run dev

---

## Developed By

Built by [vasanth642]
🔗 GitHub: @vasanth642


Support the Project

If this project helped you understand peer-to-peer streaming or accelerated your development workflow, please consider giving it a star! It helps others discover the repository.

Star this repository

About

High-performance peer-to-peer file transfer built with WebRTC. Stream large files directly between browsers with no cloud uploads, direct-to-disk streaming, backpressure control, and a modern React interface.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages