增加英文文档
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# PrivyDrop - System Architecture Overview
|
||||
|
||||
This document provides a high-level overview of the PrivyDrop project's overall architecture, helping developers understand how the various technical components work together.
|
||||
|
||||
## 1. Core Components
|
||||
|
||||
The PrivyDrop system is primarily composed of the following core parts:
|
||||
|
||||
1. **Frontend**: A Single Page Application (SPA) built with Next.js. It's the interface users interact with, responsible for handling file selection, UI presentation, and initiating WebRTC connections.
|
||||
2. **Backend**: A server built with Node.js and Express. It does not handle any file data. Its core responsibilities are:
|
||||
- **Signaling Service**: Implemented with Socket.IO, it relays signaling messages (like SDP and ICE Candidates) for the "handshake" process before a WebRTC connection is established.
|
||||
- **Room Management**: Handles the creation, joining, and status checking of rooms.
|
||||
- **API Service**: Provides auxiliary HTTP endpoints.
|
||||
3. **Redis**: An in-memory database used by the backend to store temporary data, such as room information and lists of participants, utilizing its TTL feature for automatic cleanup of expired rooms.
|
||||
4. **TURN/STUN Server (Optional)**: Used to assist WebRTC with NAT traversal, ensuring a higher success rate for P2P connections in complex network environments. STUN is used to discover public IP addresses, while TURN serves as a fallback relay server. (This feature is not enabled by default in the current setup).
|
||||
|
||||
## 2. Data Flow and Interaction Diagram
|
||||
|
||||
The following diagram illustrates the main flow for users establishing a connection and transferring files:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "User A's Browser"
|
||||
ClientA[Frontend UI]
|
||||
end
|
||||
subgraph "User B's Browser"
|
||||
ClientB[Frontend UI]
|
||||
end
|
||||
|
||||
subgraph "Server Infrastructure"
|
||||
Nginx[Nginx Reverse Proxy]
|
||||
Backend[Backend API / Socket.IO]
|
||||
Redis[Redis Cache]
|
||||
TURN[TURN/STUN Server]
|
||||
end
|
||||
|
||||
ClientA -- 1.Create/Join Room (HTTP/Socket) --> Nginx
|
||||
Nginx --> Backend
|
||||
Backend -- Read/Write Room Status --> Redis
|
||||
|
||||
ClientB -- 2.Join Same Room (HTTP/Socket) --> Nginx
|
||||
|
||||
Backend -- 3.Broadcast user join event --> ClientA
|
||||
Backend -- 3.Broadcast user join event --> ClientB
|
||||
|
||||
ClientA -- 4.Send Signal (Offer/ICE) --> Backend
|
||||
Backend -- 5.Forward Signal --> ClientB
|
||||
ClientB -- 6.Send Signal (Answer/ICE) --> Backend
|
||||
Backend -- 7.Forward Signal --> ClientA
|
||||
|
||||
ClientA <-.-> |8.STUN Check| TURN
|
||||
ClientB <-.-> |8.STUN Check| TURN
|
||||
|
||||
ClientA <-..- |9.P2P Direct Data Transfer| ClientB
|
||||
ClientA <-.-> |9.TURN Relayed Data Transfer| TURN
|
||||
ClientB <-.-> |9.TURN Relayed Data Transfer| TURN
|
||||
```
|
||||
|
||||
**Flow Description:**
|
||||
|
||||
1. **Room Creation/Joining**: User A (the sender) requests the backend to create a unique room ID via the frontend. The backend records this room in Redis.
|
||||
2. **Sharing & Joining**: User A shares the room ID with User B via a link or QR code. User B uses this ID to request joining the room.
|
||||
3. **Signaling Exchange**:
|
||||
- Once there are two or more users in a room, they begin exchanging WebRTC signaling messages through the backend's Socket.IO service.
|
||||
- This process includes exchanging network information (ICE candidates) and session descriptions (SDP offers/answers). The backend server acts merely as a "postman" for these messages, forwarding them without understanding their content.
|
||||
4. **NAT Traversal**: The browsers use the network information obtained from the signals, along with STUN/TURN servers, to attempt and establish a direct P2P connection.
|
||||
5. **P2P Connection Established**: Once the connection is successfully established, all file and text data are transferred directly between User A's and User B's browsers, without passing through any server. If a direct connection fails, data will be relayed through a TURN server.
|
||||
|
||||
## 3. Design Philosophy
|
||||
|
||||
- **Privacy First**: Core file data is never uploaded to the server. The server only acts as an "introducer" or "matchmaker."
|
||||
- **Frontend-Backend Separation**: Responsibilities are clearly separated. The frontend handles all user interaction and the complex logic of WebRTC; the backend provides lightweight, efficient signaling and room management services.
|
||||
- **Horizontal Scalability**: The backend is stateless (with state managed in Redis), which theoretically allows it to be scaled horizontally by adding more Node.js instances to handle a large volume of concurrent signaling requests.
|
||||
@@ -0,0 +1,135 @@
|
||||
# PrivyDrop - Backend Architecture Deep Dive
|
||||
|
||||
## 1. Overview
|
||||
|
||||
### 1.1 Core Responsibilities
|
||||
|
||||
The PrivyDrop backend is a lightweight server built on Node.js and Express.js. Its core responsibility is **not to transfer files directly** but to act as a "**Signaling Server**" and "**Room Coordinator**" for establishing WebRTC connections.
|
||||
|
||||
Its main functions include:
|
||||
|
||||
- **HTTP API Service**: Provides RESTful interfaces for creating, querying, and checking the status of rooms.
|
||||
- **WebRTC Signaling**: Utilizes Socket.IO to relay signaling messages (SDP Offers/Answers, ICE Candidates) between clients in real-time to facilitate P2P connections.
|
||||
- **Room Lifecycle Management**: Efficiently manages the state of rooms and participants using Redis, leveraging its TTL mechanism for automatic cleanup.
|
||||
- **Basic Security**: Implements IP-based rate limiting to prevent service abuse.
|
||||
|
||||
### 1.2 Design Principles
|
||||
|
||||
- **Stateless**: The backend service itself does not hold any state related to rooms or users. All state is delegated to an external Redis service, which allows the backend application to be easily scaled horizontally.
|
||||
- **Lightweight Signaling**: The server acts only as a relay for signaling messages. It does not parse or store the content of these signals, ensuring the privacy of end-to-end communication.
|
||||
- **High Efficiency & Low Latency**: Employs Redis as an in-memory database for room state management and Socket.IO for real-time communication to minimize the latency of signal exchange.
|
||||
- **Single Responsibility**: Each module (API, Socket handling, Redis service) has a clear and single responsibility, making it easy to understand, maintain, and test.
|
||||
|
||||
## 2. Project Structure
|
||||
|
||||
The backend source code is organized by functional modules, primarily located in the `src/` directory:
|
||||
|
||||
```
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── config/ # Environment variables and server configuration (CORS)
|
||||
│ │ ├── env.ts
|
||||
│ │ └── server.ts
|
||||
│ ├── routes/ # API route definitions (Express router)
|
||||
│ │ └── api.ts
|
||||
│ ├── services/ # Core business logic (Room, Redis, Rate Limiting)
|
||||
│ │ ├── rateLimit.ts
|
||||
│ │ ├── redis.ts
|
||||
│ │ └── room.ts
|
||||
│ ├── socket/ # Socket.IO event handlers and signaling logic
|
||||
│ │ └── handlers.ts
|
||||
│ ├── types/ # TypeScript type definitions and interfaces
|
||||
│ │ ├── room.ts
|
||||
│ │ └── socket.ts
|
||||
│ └── server.ts # Main application entry point: Express and Socket.IO setup
|
||||
├── ecosystem.config.js # PM2 configuration file
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
## 3. Core Module Deep Dive
|
||||
|
||||
### 3.1 Application Entry Point (`src/server.ts`)
|
||||
|
||||
This is the application's startup file. It is responsible for:
|
||||
|
||||
1. Loading environment variables.
|
||||
2. Initializing the Express application instance.
|
||||
3. Configuring middleware such as CORS and JSON parsing.
|
||||
4. Mounting the `/api` routes.
|
||||
5. Creating an HTTP server and attaching the Socket.IO service to it.
|
||||
6. Calling `initializeSocketHandlers` to set up all Socket.IO event listeners.
|
||||
7. Starting the server and listening on the specified port.
|
||||
|
||||
### 3.2 API Routes (`src/routes/api.ts`)
|
||||
|
||||
Defines all the HTTP RESTful APIs called by the frontend.
|
||||
|
||||
- **`POST /api/create_room`**: Receives a `roomId` specified by the frontend, checks for its availability, and creates a new room if available.
|
||||
- **`GET /api/get_room`**: Generates a unique, random room ID, creates the room, and returns it to the frontend.
|
||||
- **`POST /api/check_room`**: Checks if a given `roomId` already exists.
|
||||
- **`POST /api/set_track`**: Used to track traffic sources (referrers).
|
||||
- **`POST /api/logs_debug`**: A simple debugging endpoint to receive logs from the frontend and print them on the backend console.
|
||||
|
||||
### 3.3 Socket.IO Event Handling (`src/socket/handlers.ts`)
|
||||
|
||||
This is the core of the signaling exchange. The `initializeSocketHandlers` function binds a series of event handlers to an incoming `socket` connection.
|
||||
|
||||
- **Connection & Disconnection**:
|
||||
- `connection`: Logs the `socket.id` when a new client connects.
|
||||
- `disconnect`: When a client disconnects, it is removed from the room it was in, and other peers in the room are notified (`peer-disconnected`).
|
||||
- **Room Logic**:
|
||||
- **`join`**: Handles a client's request to join a room. It verifies if the room exists, adds the client's `socket.id` to the room's set of members, and finally sends a `joinResponse` to the requester.
|
||||
- **`initiator-online`**: Emitted by the room creator (initiator), often when the app comes back from being backgrounded, to notify the recipient, "I'm online, let's re-establish the connection."
|
||||
- **`recipient-ready`**: Emitted by the recipient to notify the initiator in the room, "I'm ready, you can start the reconnection process," which typically signals the start of the WebRTC `offer` flow.
|
||||
- **WebRTC Signaling Forwarding**:
|
||||
- **`offer`**, **`answer`**, **`ice-candidate`**: These three events are pure relays. They are responsible for accurately forwarding a peer's WebRTC signaling message to the other peer in the room.
|
||||
|
||||
### 3.4 Service Layer (`src/services/`)
|
||||
|
||||
Encapsulates interactions with external dependencies (like Redis) and core business logic.
|
||||
|
||||
- **`redis.ts`**: Provides a singleton instance of the Redis client. All interactions with Redis should go through this module.
|
||||
- **`room.ts`**: Encapsulates all room-related Redis operations, such as `createRoom`, `isRoomExist`, `bindSocketToRoom`, etc. It decouples business logic (e.g., "add user to room") from the underlying Redis commands (e.g., `SADD`, `HSET`).
|
||||
- **`rateLimit.ts`**: Implements a rate limiter based on IP address and a Redis Sorted Set to restrict users from creating or joining rooms too frequently in a short period.
|
||||
|
||||
## 4. Redis Data Structure Deep Dive
|
||||
|
||||
Redis is a key component of the backend, used to store all temporary state. We cleverly use different data structures to meet business needs and set a TTL for all keys to ensure automatic data cleanup.
|
||||
|
||||
- **1. Room Information (`Hash`)**:
|
||||
|
||||
- **Key Pattern**: `room:<roomId>` (e.g., `room:ABCD12`)
|
||||
- **Purpose**: Stores the metadata of a room.
|
||||
- **Fields**:
|
||||
- `created_at`: Timestamp of when the room was created.
|
||||
- **Example**: `HSET room:ABCD12 created_at 1705123456789`
|
||||
|
||||
- **2. Sockets in a Room (`Set`)**:
|
||||
|
||||
- **Key Pattern**: `room:<roomId>:sockets` (e.g., `room:ABCD12:sockets`)
|
||||
- **Purpose**: Stores all client `socketId`s within a single room. Using a Set guarantees the uniqueness of members and makes additions and removals convenient.
|
||||
- **Members**: The client's `socketId`.
|
||||
- **Example**: `SADD room:ABCD12:sockets "socketId_A" "socketId_B"`
|
||||
|
||||
- **3. Socket-to-Room Mapping (`String`)**:
|
||||
|
||||
- **Key Pattern**: `socket:<socketId>` (e.g., `socket:xgACY6QcQCojsOQaAAAB`)
|
||||
- **Purpose**: Provides a reverse mapping from a `socketId` to its `roomId`. This is very useful when handling client disconnections, as we can quickly find the room and perform cleanup using only the `socketId`.
|
||||
- **Value**: The `roomId`.
|
||||
- **Example**: `SET socket:xgACY6QcQCojsOQaAAAB ABCD12`
|
||||
|
||||
- **4. Rate Limiting (`Sorted Set`)**:
|
||||
|
||||
- **Key Pattern**: `ratelimit:join:<ipAddress>` (e.g., `ratelimit:join:192.168.1.100`)
|
||||
- **Purpose**: Records all request timestamps from a specific IP address within a given time window.
|
||||
- **Members**: `timestamp-randomNumber` (e.g., `1678886400000-0.12345`). A random number suffix is used to ensure uniqueness for multiple requests within the same millisecond.
|
||||
- **Score**: The Unix timestamp of the request (in milliseconds).
|
||||
- **Logic**: Old records outside the time window are removed using `ZREMRANGEBYSCORE`, and then the number of requests within the window is counted with `ZCARD` to determine if the limit has been exceeded.
|
||||
|
||||
- **5. Referrer Tracking (`Hash`)**:
|
||||
- **Key Pattern**: `referrers:daily:<YYYY-MM-DD>` (e.g., `referrers:daily:2023-03-15`)
|
||||
- **Purpose**: Tracks the number of visits from different sources (Referrers) on a daily basis.
|
||||
- **Fields**: The referrer's domain name (e.g., `google.com`, `github.com`).
|
||||
- **Value**: The cumulative visit count for the day.
|
||||
- **Logic**: The `HINCRBY` command is used to atomically increment the count for a specified source.
|
||||
@@ -0,0 +1,250 @@
|
||||
# PrivyDrop Deployment Guide
|
||||
|
||||
This guide provides comprehensive instructions for deploying the full-stack PrivyDrop application, including setting up Redis, a TURN server, the backend service, the frontend application, and configuring Nginx as a reverse proxy.
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
This document will guide you through preparing your server environment, configuring dependencies, and deploying both the frontend and backend of PrivyDrop. Whether you are setting up a development/testing environment or a full production instance, this guide aims to cover all essential aspects.
|
||||
|
||||
## 2. Prerequisites
|
||||
|
||||
Before you begin, please ensure your server environment meets the following requirements:
|
||||
|
||||
- **Operating System:** A Linux distribution (e.g., Ubuntu 20.04 LTS or newer is recommended).
|
||||
- **Node.js:** v18.x or higher.
|
||||
- **npm (or yarn/pnpm):** The package manager for Node.js.
|
||||
- **Root or Sudo Privileges:** Required for installing packages and configuring services.
|
||||
- **Domain Name:** Required for a production deployment.
|
||||
- **Optional: Base Environment & Docker Image Reference:** If you are starting from a very clean system environment or wish to see the base dependencies for a Docker build, you can refer to the `backend/docker/Dockerfile` (for Docker image creation) and `backend/docker/env_install.log` (dependency installation log) files.
|
||||
|
||||
## 3. Dependency Services: Installation & Configuration
|
||||
|
||||
### 3.1. Redis Server
|
||||
|
||||
Redis is used by the backend for room management, session information, and caching.
|
||||
|
||||
**Installation (Ubuntu Example):**
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install redis-server
|
||||
```
|
||||
|
||||
**Configuration:**
|
||||
|
||||
- By default, Redis listens on `127.0.0.1:6379` without a password. Ensure your backend's `.env` file includes the correct `REDIS_HOST` and `REDIS_PORT`.
|
||||
- Verify that Redis is running: `sudo systemctl status redis-server`
|
||||
- If it's not running, start it: `sudo systemctl start redis-server`
|
||||
|
||||
### 3.2. TURN/STUN Server (Coturn)
|
||||
|
||||
**Important: This section is optional.** By default, PrivyDrop uses public STUN servers, which are sufficient to establish connections in most network environments. You only need to set up your own TURN server if you have extremely high requirements for NAT traversal success rates.
|
||||
|
||||
A TURN server is crucial for WebRTC to traverse NATs and firewalls. Coturn is a popular implementation.
|
||||
|
||||
**Installation (Ubuntu Example):**
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install coturn
|
||||
```
|
||||
|
||||
**Configuration:**
|
||||
|
||||
1. **Enable the Coturn service:** Edit `/etc/default/coturn` and uncomment `TURNSERVER_ENABLED=1`.
|
||||
2. **Firewall Configuration:** Open the necessary ports on your server's firewall (e.g., using `ufw`):
|
||||
- TCP & UDP `3478`: For STUN and TURN.
|
||||
- TCP & UDP `5349`: For TURNS (TURN over TLS/DTLS) - **Production**.
|
||||
- UDP `49152-65535`: Coturn's default relay port range.
|
||||
```bash
|
||||
sudo ufw allow 3478
|
||||
sudo ufw allow 5349
|
||||
sudo ufw allow 49152:65535/udp
|
||||
sudo ufw enable
|
||||
```
|
||||
3. **Production SSL Certificate (for TURNS):**
|
||||
Obtain an SSL certificate for your TURN domain (e.g., `turn.yourdomain.com`).
|
||||
```bash
|
||||
# Ensure a DNS 'A' record points turn.yourdomain.com to your server's IP
|
||||
sudo apt install certbot
|
||||
sudo certbot certonly --standalone -d turn.yourdomain.com
|
||||
```
|
||||
4. **SSL Certificate Permissions:**
|
||||
The Coturn process (usually runs as the `turnserver` user) needs permission to read the SSL certificate and private key.
|
||||
|
||||
- Check current permissions:
|
||||
```bash
|
||||
sudo ls -lh /etc/letsencrypt/live/turn.yourdomain.com/fullchain.pem
|
||||
sudo ls -ld /etc/letsencrypt/archive/
|
||||
```
|
||||
- If Coturn logs show permission errors:
|
||||
Create a group (e.g., `ssl-cert`), add `turnserver` to it, and adjust permissions:
|
||||
```bash
|
||||
sudo groupadd -f ssl-cert
|
||||
# Find the user coturn runs as, usually 'turnserver' or 'coturn'
|
||||
# ps aux | grep turnserver
|
||||
sudo usermod -a -G ssl-cert turnserver # Replace 'turnserver' if different
|
||||
sudo chown -R root:ssl-cert /etc/letsencrypt/
|
||||
sudo chmod -R 750 /etc/letsencrypt/
|
||||
```
|
||||
Verify the new permissions on `/etc/letsencrypt/archive/` and `/etc/letsencrypt/live/`.
|
||||
|
||||
5. **Configure and Start Coturn:**
|
||||
|
||||
- Configure `TURN_*` related environment variables in the backend's `.env` file (e.g., username, password, certificate paths).
|
||||
- For a **testing environment**, you need to set:
|
||||
```
|
||||
TURN_EXTERNAL_IP=YourServerPublicIP # e.g., 123.123.456.567
|
||||
TURN_REALM=YourServerPublicIP
|
||||
TURN_USERNAME=YourTurnUsername
|
||||
TURN_PASSWORD=YourTurnPassword
|
||||
```
|
||||
- For a **production deployment**, you need to set:
|
||||
```
|
||||
TURN_EXTERNAL_IP=YourServerPublicIP # e.g., 123.123.456.567
|
||||
TURN_REALM=turn.yourdomain
|
||||
TURN_USERNAME=YourTurnUsername
|
||||
TURN_PASSWORD=YourTurnPassword
|
||||
TURN_CERT_PATH=/etc/letsencrypt/live/turn.yourdomain/fullchain.pem
|
||||
TURN_KEY_PATH=/etc/letsencrypt/live/turn.yourdomain/privkey.pem
|
||||
```
|
||||
- Use the script provided in the project to generate the configuration file and start the service:
|
||||
|
||||
```bash
|
||||
# Located in the backend/ directory
|
||||
sudo bash ./docker/TURN/configure.sh path/to/your/.env.production.local
|
||||
# For a development environment, use .env.development.local
|
||||
sudo systemctl status coturn
|
||||
```
|
||||
|
||||
- Check the logs at `/var/log/turnserver.log` to confirm there are no errors.
|
||||
|
||||
6. **Online Testing (Optional):**
|
||||
Use an online tool like the Metered TURN Server Tester (https://www.metered.ca/turn-server-testing):
|
||||
|
||||
- **For Development/Testing (non-TLS):**
|
||||
- TURN URL: `YourServerPublicIP`
|
||||
- TURN Port: `3478`
|
||||
- Username: `YourTurnUsername`
|
||||
- Password: `YourTurnPassword`
|
||||
- **For Production (TURNS):**
|
||||
- TURNS URL: `turn.yourdomain.com`
|
||||
- TURNS Port: `5349`
|
||||
- Username: `YourTurnUsername`
|
||||
- Password: `YourTurnPassword`
|
||||
|
||||
A successful test should show a "Reachable" message.
|
||||
|
||||
## 4. Application Deployment (Production)
|
||||
|
||||
This section describes how to deploy PrivyDrop in a production environment using Nginx and PM2.
|
||||
|
||||
### 4.1. Get the Code and Install Dependencies
|
||||
|
||||
```bash
|
||||
git clone <your-repository-url> privydrop
|
||||
cd privydrop
|
||||
|
||||
# Install backend dependencies
|
||||
cd backend && npm install && cd ..
|
||||
|
||||
# Install frontend dependencies
|
||||
cd frontend && pnpm install && cd ..
|
||||
```
|
||||
|
||||
### 4.2. Configure Environment Variables
|
||||
|
||||
- **Backend:**
|
||||
- Create a `.env.production.local` file in the `backend/` directory.
|
||||
- Fill in the necessary environment variables (e.g., `PORT`, `REDIS_HOST`, `REDIS_PORT`, `CORS_ORIGIN`).
|
||||
- For Nginx integration, also add `NGINX_SERVER_NAME`, `NGINX_SSL_CERT`, `NGINX_SSL_KEY`, and `NGINX_FRONTEND_ROOT`.
|
||||
- **Frontend:**
|
||||
- Create a `.env.production.local` file in the `frontend/` directory.
|
||||
- Fill in the `NEXT_PUBLIC_API_URL` variable.
|
||||
|
||||
### 4.3. Build the Frontend Application
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
pnpm build
|
||||
```
|
||||
|
||||
This will generate an optimized production build in the `frontend/.next` directory.
|
||||
|
||||
### 4.4. Run the Application with PM2
|
||||
|
||||
PM2 is a powerful process manager for Node.js. We will use it to run the backend and frontend services separately.
|
||||
|
||||
1. **Install PM2 globally:**
|
||||
|
||||
```bash
|
||||
sudo npm install -g pm2
|
||||
```
|
||||
|
||||
2. **Start the Backend Service:**
|
||||
The backend directory provides an `ecosystem.config.js` file for PM2.
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
# Ensure .env.production.local is fully configured
|
||||
pm2 start ecosystem.config.js
|
||||
```
|
||||
|
||||
3. **Start the Frontend Service:**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
pm2 start npm --name "privydrop-frontend" -- run start
|
||||
```
|
||||
|
||||
The `npm start` command starts the Next.js production server, which listens on port 3000 by default.
|
||||
|
||||
4. **Manage Applications:**
|
||||
- View status: `pm2 list`
|
||||
- View logs: `pm2 logs <app_name>`
|
||||
- Set up startup script: `pm2 startup` followed by `pm2 save`
|
||||
|
||||
### 4.5. Configure Nginx as a Reverse Proxy
|
||||
|
||||
In production, Nginx will act as the entry point for all traffic, handling SSL termination and routing requests to the correct frontend or backend service.
|
||||
|
||||
1. **Install Nginx:** It's recommended to install a newer version that supports HTTP/3.
|
||||
|
||||
2. **Firewall:** Ensure ports `TCP:80 (HTTP)` and `TCP/UDP:443 (HTTPS/HTTP3)` are open.
|
||||
|
||||
3. **Main Domain SSL Certificate:** Obtain a certificate for your main domain (e.g., `yourdomain.com`).
|
||||
|
||||
```bash
|
||||
sudo apt install python3-certbot-nginx
|
||||
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
|
||||
```
|
||||
|
||||
4. **Nginx Configuration File:**
|
||||
The `backend/docker/Nginx/` directory in the project provides a configuration script and template.
|
||||
|
||||
- Add the `NGINX_*` related variables to your backend's `.env.production.local` file, including the domain, certificate paths, and the **root directory of the frontend build artifacts**. Example:
|
||||
|
||||
```
|
||||
NGINX_SERVER_NAME=yourdomain.com # The full domain name
|
||||
NGINX_SSL_CERT=/etc/letsencrypt/live/yourdomain.com/fullchain.pem
|
||||
NGINX_SSL_KEY=/etc/letsencrypt/live/yourdomain.com/privkey.pem
|
||||
NGINX_FRONTEND_ROOT=/path/to/your/frontend/.next # Path to frontend build output
|
||||
```
|
||||
|
||||
5. **Apply Configuration:** Generate the Nginx config, create a symbolic link, and restart Nginx.
|
||||
```bash
|
||||
# This script uses NGINX_* variables from your .env file to generate the Nginx config
|
||||
sudo bash backend/docker/Nginx/configure.sh backend/.env.production.local
|
||||
```
|
||||
|
||||
## 5. Troubleshooting
|
||||
|
||||
- **Connection Issues:** Check firewall settings, Nginx proxy configurations, `CORS_ORIGIN` settings, and ensure all PM2 processes are running.
|
||||
- **Nginx Errors:** Use `sudo nginx -t` to check syntax and review `/var/log/nginx/error.log`.
|
||||
- **PM2 Issues:** Use `pm2 logs <app_name>` to view application logs.
|
||||
- **Certificate Permissions (Production):** If Coturn or Nginx cannot read SSL certificates, carefully check file permissions and user/group settings.
|
||||
|
||||
## 6. Security & Maintenance
|
||||
|
||||
- **SSL Certificate Renewal (Production):** You can refer to the `backend/docker/Nginx/renew_ssl.sh` script to automate renewal.
|
||||
- **Firewall:** Maintain strict firewall rules, only allowing necessary ports.
|
||||
@@ -0,0 +1,144 @@
|
||||
# PrivyDrop Frontend Architecture Documentation
|
||||
|
||||
## 1. Architecture Overview
|
||||
|
||||
### 1.1 Project Vision
|
||||
|
||||
PrivyDrop is a P2P file/text sharing tool based on WebRTC, designed to provide a secure, private, and efficient online sharing solution. The core objective of the frontend architecture is to build a high-performance, maintainable, and scalable modern web application, adhering to Next.js best practices.
|
||||
|
||||
### 1.2 Design Philosophy
|
||||
|
||||
In a recent refactor, we established a design philosophy centered on "**Separation of Concerns**" and "**Logical Cohesion**":
|
||||
|
||||
- **UI and Logic Separation**: Views (Components) should remain as "pure" as possible, responsible only for rendering the UI and responding to user interactions. All complex business logic, state management, and side effects should be extracted from components.
|
||||
- **Hooks as the Core of Business Logic**: Custom React Hooks are first-class citizens for organizing our business logic and state. Each Hook encapsulates a distinct, cohesive functional module (e.g., WebRTC connection, room management), making the logic unit reusable, testable, and significantly simplifying the component tree.
|
||||
- **Layered Architecture**: The codebase follows a clear, layered structure, ensuring that each layer has a single responsibility, reducing coupling between modules.
|
||||
|
||||
### 1.3 Core Tech Stack
|
||||
|
||||
- **Framework**: Next.js 14 (App Router)
|
||||
- **Language**: TypeScript
|
||||
- **UI**: React 18, Tailwind CSS, shadcn/ui (based on Radix UI)
|
||||
- **State Management**: Modular state management centered on custom React Hooks
|
||||
- **WebRTC Signaling**: Socket.IO Client
|
||||
- **Data Fetching**: React Server Components (RSC), Fetch API
|
||||
- **Internationalization**: `next/server` middleware + dynamic JSON dictionaries
|
||||
- **Content**: MDX (for blog and static content pages)
|
||||
|
||||
### 1.4 High-Level Layered Model
|
||||
|
||||
The frontend architecture can be broadly divided into four layers:
|
||||
|
||||
```
|
||||
+---------------------------------------------------+
|
||||
| ① Application & Routing Layer (App Router) | app/
|
||||
| (Pages, Layouts, Routing, i18n Middleware) |
|
||||
+---------------------------------------------------+
|
||||
| ② UI & Component Layer | components/
|
||||
| (Coordinator Components, UI Panels, Common |
|
||||
| Components, Base UI Elements) |
|
||||
+---------------------------------------------------+
|
||||
| ③ Business Logic & State Layer (Hooks) | hooks/
|
||||
| (WebRTC Connection, Room Management, File |
|
||||
| Transfer, Clipboard Operations, etc.) |
|
||||
+---------------------------------------------------+
|
||||
| ④ Core Libraries & Utilities Layer | lib/
|
||||
| (Low-level WebRTC Wrappers, File Handling, |
|
||||
| Utility Functions, API Client) |
|
||||
+---------------------------------------------------+
|
||||
```
|
||||
|
||||
- **① Application & Routing Layer**: Managed by the Next.js App Router, responsible for page rendering, route control, internationalization, and initial data fetching.
|
||||
- **② UI & Component Layer**: Responsible for displaying the entire user interface. It consumes state and methods from the layer below (Hooks) and propagates user interaction events upward.
|
||||
- **③ Business Logic & State Layer**: **This is the "brain" of the application**. It encapsulates all core functional business logic and state through a series of custom Hooks.
|
||||
- **④ Core Libraries & Utilities Layer**: Provides the lowest-level, framework-agnostic, pure functions, such as low-level WebRTC wrappers and API requests.
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Feature Implementation: P2P File/Text Transfer
|
||||
|
||||
This section details how the application's most critical P2P transfer feature is implemented through the collaboration of different architectural layers.
|
||||
|
||||
### 2.1 Overall Flow
|
||||
|
||||
1. **User Action (`components`)**: The user performs an action in `SendTabPanel` or `RetrieveTabPanel` (e.g., selecting a file, entering a room code).
|
||||
2. **Logic Processing (`hooks`)**: Hooks like `useFileTransferHandler` and `useRoomManager` capture these actions, manage related state (e.g., the list of files to be sent), and invoke connection methods provided by the `useWebRTCConnection` Hook.
|
||||
3. **Connection Establishment (`hooks` -> `lib`)**: `useWebRTCConnection` calls low-level functions in `lib/webrtc_*.ts` to negotiate with the peer via the Socket.IO signaling server and establish an `RTCPeerConnection`.
|
||||
4. **Data Transfer (`lib`)**: Once the connection is established, `lib/fileSender.ts` and `lib/fileReceiver.ts` are responsible for chunking, serializing, and transferring the file over the `RTCDataChannel`.
|
||||
5. **State Updates & Callbacks (`lib` -> `hooks` -> `components`)**: During the transfer, the `lib` layer notifies the `hooks` layer of state changes (e.g., progress updates) via callbacks. These state changes in the `hooks` layer ultimately trigger a re-render of the `components` layer's UI.
|
||||
|
||||
### 2.2 Module Deep Dive
|
||||
|
||||
- **Low-Level WebRTC Wrappers (`lib/`)**:
|
||||
|
||||
- `webrtc_base.ts`: Encapsulates interactions with the Socket.IO signaling server, generic management of `RTCPeerConnection` (ICE, connection state), and the creation of `RTCDataChannel`. It is the foundation for all WebRTC operations.
|
||||
- `fileSender.ts` / `fileReceiver.ts`: Handle the logic for sending and receiving files/text, including metadata exchange, file chunking, progress calculation, data reassembly, and file saving.
|
||||
|
||||
- **WebRTC Business Logic Wrappers (`hooks/`)**:
|
||||
|
||||
- `useWebRTCConnection.ts`: **The connection's "central hub"**. It initializes and manages `sender` and `receiver` instances, handles the connection lifecycle, and provides a clean API (e.g., `broadcastDataToAllPeers`) and state (e.g., `peerCount`, `sendProgress`) to the upper layers.
|
||||
- `useRoomManager.ts`: **The room's "state machine"**. It's responsible for the creation, validation (with debouncing), and joining logic for room IDs, and manages UI state text related to the room.
|
||||
- `useFileTransferHandler.ts`: **The transfer's "data center"**. It manages the text and files to be sent or received, handles user actions like adding/removing/downloading files, and provides callbacks to `useWebRTCConnection` for processing received data.
|
||||
|
||||
- **UI Coordination & Display (`components/`)**:
|
||||
- `ClipboardApp.tsx`: **The core application's "main coordinator"**. It contains no business logic itself. Its sole responsibility is to integrate all the core Hooks mentioned above and then distribute the state and callbacks obtained from these Hooks as props to specific UI sub-components.
|
||||
- `SendTabPanel.tsx` / `RetrieveTabPanel.tsx`: Purely presentational components responsible for rendering the send and receive panels and responding to user input.
|
||||
- `FileListDisplay.tsx`: Used to display the file list and transfer status.
|
||||
|
||||
## 3. Application Layer Detailed Architecture
|
||||
|
||||
### 3.1 Directory Structure & Responsibilities
|
||||
|
||||
- **`frontend/app/`**: Core application routes and pages.
|
||||
|
||||
- `[lang]/`: Implements multi-language dynamic routing.
|
||||
- `layout.tsx`: Global layout, provides Providers (Theme, i18n).
|
||||
- `page.tsx`: Main page entry point, renders `HomeClient`.
|
||||
- `HomeClient.tsx`: (Client Component) Hosts the core `ClipboardApp` and other marketing/display components.
|
||||
- `config/`: Application configuration.
|
||||
- `api.ts`: Centralizes interaction with the backend API.
|
||||
- `environment.ts`: Manages environment variables and runtime configurations (like ICE servers).
|
||||
|
||||
- **`frontend/components/`**: UI component library.
|
||||
|
||||
- `ClipboardApp/`: All UI sub-components broken down from `ClipboardApp`. **Implements separation of concerns**.
|
||||
- `common/`: Reusable components that can be used across the project (e.g., `YouTubePlayer`).
|
||||
- `ui/`: (from shadcn/ui) Base atomic components.
|
||||
- `web/`: Large, page-level static components for the website (e.g., `Header`, `Footer`).
|
||||
- `Editor/`: Custom rich text editor.
|
||||
|
||||
- **`frontend/hooks/`**: **The core of business logic and state management**. Detailed above.
|
||||
|
||||
- **`frontend/lib/`**: Core libraries and utility functions.
|
||||
|
||||
- `webrtc_*.ts`, `fileSender.ts`, `fileReceiver.ts`: WebRTC core.
|
||||
- `dictionary.ts`: Internationalization dictionary loading.
|
||||
- `utils.ts`, `fileUtils.ts`: General utility functions.
|
||||
|
||||
- **`frontend/types/`**: Global TypeScript type definitions.
|
||||
|
||||
- **`frontend/constants/`**: Application-wide constants, mainly for i18n configuration and message files.
|
||||
|
||||
### 3.2 State Management Strategy
|
||||
|
||||
The project uses **custom React Hooks as the core for modular state management**. We deliberately avoided introducing global state management libraries (like Redux or Zustand) for the following reasons:
|
||||
|
||||
- **Reduce Complexity**: For the current scale of the application, a global state would introduce unnecessary complexity.
|
||||
- **Promote Cohesion**: Encapsulating related state and logic within the same Hook makes the code easier to understand and maintain.
|
||||
- **Leverage React's Native Capabilities**: Passing state managed by Hooks through Context and Props is sufficient for all current needs.
|
||||
|
||||
### 3.3 Internationalization (i18n)
|
||||
|
||||
- **Route-Driven**: Language switching is implemented via the URL path (`/[lang]/`).
|
||||
- **Automatic Detection**: `middleware.ts` intercepts requests and automatically redirects to the appropriate language path based on the `Accept-Language` header or a cookie.
|
||||
- **Dynamic Loading**: The `getDictionary` function in `lib/dictionary.ts` asynchronously loads the corresponding `messages/*.json` file based on the `lang` parameter, enabling code splitting.
|
||||
|
||||
## 4. Summary and Outlook
|
||||
|
||||
The current frontend architecture successfully deconstructs a complex WebRTC application into a series of clean, maintainable modules through layered design and Hook-centric logic encapsulation. The boundaries between UI, business logic, and underlying libraries are clear, laying a solid foundation for future feature expansion and maintenance.
|
||||
|
||||
Future areas for optimization include:
|
||||
|
||||
- **Adding Unit/Integration Tests**: Writing test cases for core Hooks (`useWebRTCConnection`, etc.) and utility classes in `lib`.
|
||||
- **Bundle Analysis**: Regularly analyzing the bundle size with `@next/bundle-analyzer` to identify optimization opportunities.
|
||||
- **Component Library Enhancement**: Continuously refining and polishing the common components in `components/common`.
|
||||
Reference in New Issue
Block a user