forked from snxraven/ravenscott-blog
282 lines
11 KiB
Markdown
282 lines
11 KiB
Markdown
|
<!-- lead -->
|
||
|
A Deep Dive into Decentralized Peer-to-Peer Chat Architecture
|
||
|
|
||
|
## Introduction
|
||
|
|
||
|
In the modern age of centralized messaging systems, privacy and decentralization have become critical topics. LinkUp addresses these concerns by providing a peer-to-peer (P2P) chat application built on decentralized networking libraries. LinkUp eliminates the need for centralized servers, relying instead on peer-to-peer connections to enable direct communication between users. This article delves into the technical architecture, key components, and development process behind LinkUp, explaining how it utilizes **Hyperswarm**, **Hyperdrive**, **Corestore**, and related technologies to create a fully decentralized chat experience.
|
||
|
|
||
|
# Source
|
||
|
## https://git.ssh.surf/snxraven/LinkUp-P2P-Chat
|
||
|
|
||
|
# Screenshot
|
||
|
![Screenshot](https://git.ssh.surf/snxraven/LinkUp-P2P-Chat/media/branch/main/images/screenshot.png)
|
||
|
|
||
|
|
||
|
## Technology Stack
|
||
|
|
||
|
LinkUp is built using a collection of robust libraries that are specifically designed for decentralized networking and storage:
|
||
|
|
||
|
- **Hyperswarm**: Provides peer-to-peer networking by using Distributed Hash Tables (DHTs) for peer discovery and communication. It enables users to discover peers dynamically using public or private topics.
|
||
|
- **Hyperdrive**: A file system that supports decentralized storage and real-time collaboration. Hyperdrive creates file-based networks with automatic versioning, allowing efficient sharing of files.
|
||
|
- **Corestore**: Acts as a storage system for the data and drives used by the application. Corestore provides a way to group and organize the cores used in Hyperdrive.
|
||
|
- **EventEmitter**: Facilitates event-driven architecture, enabling smooth handling of user interactions, peer communication, and command processing.
|
||
|
- **MarkdownIt** and **highlight.js**: Used for rendering Markdown messages with syntax highlighting in the chat.
|
||
|
|
||
|
The application also uses **fs**, **crypto**, and **b4a** (Buffer allocation) for file management, encryption, and buffer handling, making it highly secure and efficient.
|
||
|
|
||
|
|
||
|
|
||
|
## Project Structure
|
||
|
|
||
|
The project's source code is modular and organized as follows:
|
||
|
|
||
|
```plaintext
|
||
|
LinkUp-P2P-Chat/
|
||
|
├── app.js # Main application logic
|
||
|
├── commands.js # Command handling logic
|
||
|
├── index.html # HTML structure for the web interface
|
||
|
├── style.css # CSS for styling the web interface
|
||
|
├── config.json # Configuration file to store user/room data
|
||
|
├── assets/ # Static assets such as avatars and icons
|
||
|
├── storage/ # Decentralized file storage (managed by Hyperdrive)
|
||
|
├── chatBot/ # Bot integration with Hyperswarm network
|
||
|
├── README.md # Project documentation
|
||
|
```
|
||
|
|
||
|
Key components include:
|
||
|
|
||
|
- **app.js**: Handles core application functionality such as peer discovery, event handling, and message transmission.
|
||
|
- **commands.js**: Contains the logic for user commands like `~ping`, `~clear`, `~join`, `~create`, and more.
|
||
|
- **config.json**: A JSON file that stores user information, chat room details, and registered users.
|
||
|
- **chatBot**: A bot that runs alongside the P2P application to automate tasks and respond to messages.
|
||
|
|
||
|
|
||
|
|
||
|
## Peer-to-Peer Networking with Hyperswarm
|
||
|
|
||
|
The backbone of LinkUp's communication lies in **Hyperswarm**, a peer-to-peer networking library designed for dynamic peer discovery using **topics**. Topics are 32-byte identifiers that represent chat rooms or guilds in the LinkUp application.
|
||
|
|
||
|
### Joining a Swarm
|
||
|
|
||
|
When a user joins a chat room, the following steps occur:
|
||
|
|
||
|
1. A unique topic is generated or used for the chat room. This is represented by a hash string.
|
||
|
2. The user joins the **swarm** associated with that topic:
|
||
|
```javascript
|
||
|
const swarm = new Hyperswarm();
|
||
|
const discovery = swarm.join(topicBuffer, { client: true, server: true });
|
||
|
```
|
||
|
3. Peers connected to the same topic can establish direct connections and begin exchanging messages.
|
||
|
|
||
|
### Handling Connections
|
||
|
|
||
|
Once peers are discovered, **Hyperswarm** establishes encrypted connections between them. The `handleConnection` function sets up event listeners for incoming data, allowing messages, files, and audio to be transmitted between peers.
|
||
|
|
||
|
```javascript
|
||
|
swarm.on('connection', (connection, info) => {
|
||
|
handleConnection(connection, info);
|
||
|
});
|
||
|
|
||
|
function handleConnection(connection, info) {
|
||
|
connection.on('data', (data) => {
|
||
|
const messageObj = JSON.parse(data.toString());
|
||
|
eventEmitter.emit('onMessage', messageObj, connection);
|
||
|
});
|
||
|
|
||
|
connection.on('close', () => {
|
||
|
updatePeerCount();
|
||
|
});
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
## Decentralized Storage with Hyperdrive and Corestore
|
||
|
|
||
|
**Hyperdrive** is used for decentralized storage of files and other media shared in the chat. All shared files are stored in a version-controlled, P2P-driven filesystem that enables users to upload, retrieve, and manage files efficiently without relying on centralized servers.
|
||
|
|
||
|
### File Uploading and Downloading
|
||
|
|
||
|
When a user uploads a file, the file is written to the local **Corestore** through **Hyperdrive**. The file is then shared with peers in the same room:
|
||
|
|
||
|
```javascript
|
||
|
async function handleFileInput(event) {
|
||
|
const file = event.target.files[0];
|
||
|
const filePath = `/files/${file.name}`;
|
||
|
|
||
|
// Store the file in the decentralized drive
|
||
|
await drive.put(filePath, buffer);
|
||
|
|
||
|
// Broadcast file message to peers
|
||
|
const fileMessage = {
|
||
|
type: 'file',
|
||
|
name: config.userName,
|
||
|
fileName: file.name,
|
||
|
file: b4a.toString(buffer, 'base64'),
|
||
|
topic: currentTopic(),
|
||
|
};
|
||
|
|
||
|
broadcastMessage(fileMessage);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### Versioning and Real-Time Collaboration
|
||
|
|
||
|
Files stored in Hyperdrive are versioned, allowing peers to access past versions of files. This is particularly useful in collaborative environments where multiple users may be editing or updating the same files.
|
||
|
|
||
|
|
||
|
|
||
|
## Handling Commands and Events
|
||
|
|
||
|
LinkUp supports a command-based interface where users can execute various actions like creating chat rooms, clearing messages, and sending pings.
|
||
|
|
||
|
### Command Parsing
|
||
|
|
||
|
Commands are parsed by checking if the user's input starts with a specific prefix (`~`). The command is then routed to the appropriate handler in `commands.js`.
|
||
|
|
||
|
```javascript
|
||
|
async function sendMessage(e) {
|
||
|
e.preventDefault();
|
||
|
const message = document.querySelector('#message').value;
|
||
|
|
||
|
if (message.startsWith('~')) {
|
||
|
await handleCommand(message, { /* command options */ });
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Normal message handling...
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The `handleCommand` function dynamically handles different command types, such as:
|
||
|
|
||
|
- **~create [roomName]**: Creates a new chat room with the specified alias.
|
||
|
- **~join [roomTopic]**: Joins an existing room by its topic hash.
|
||
|
- **~clear**: Clears the chat history for the current room.
|
||
|
|
||
|
|
||
|
|
||
|
## File Sharing and Audio Messaging
|
||
|
|
||
|
LinkUp supports file sharing and audio messaging using a decentralized approach. Files and audio clips are stored in the **Hyperdrive** and served to peers using **ServeDrive**, a static file server for decentralized filesystems.
|
||
|
|
||
|
### Audio Recording
|
||
|
|
||
|
To record and send audio messages, LinkUp integrates with the browser's media APIs. The audio is captured, encoded, and stored in the decentralized filesystem, making it available to all peers in the chat room.
|
||
|
|
||
|
```javascript
|
||
|
mediaRecorder.addEventListener('stop', async () => {
|
||
|
const audioBlob = new Blob(audioChunks);
|
||
|
const buffer = new Uint8Array(await audioBlob.arrayBuffer());
|
||
|
|
||
|
// Store the audio file in Hyperdrive
|
||
|
const filePath = `/audio/${Date.now()}.webm`;
|
||
|
await drive.put(filePath, buffer);
|
||
|
|
||
|
// Broadcast audio message to peers
|
||
|
const audioMessage = {
|
||
|
type: 'audio',
|
||
|
name: config.userName,
|
||
|
audio: b4a.toString(buffer, 'base64'),
|
||
|
topic: currentTopic(),
|
||
|
};
|
||
|
broadcastMessage(audioMessage);
|
||
|
});
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
## Configuration and Initialization
|
||
|
|
||
|
LinkUp uses a configuration file (`config.json`) to store user data, chat room details, and registered users. This file is automatically generated and updated as users interact with the application.
|
||
|
|
||
|
### Configuration File Structure
|
||
|
|
||
|
The configuration file stores essential user data in the following structure:
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
"userName": "",
|
||
|
"userAvatar": "",
|
||
|
"rooms": [],
|
||
|
"registeredUsers": {}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
- **userName**: The user's display name.
|
||
|
- **userAvatar**: The user's avatar image URL (or base64-encoded image).
|
||
|
- **rooms**: List of rooms the user has created or joined.
|
||
|
- **registeredUsers**: A mapping of registered users and their avatars.
|
||
|
|
||
|
### Initializing the Application
|
||
|
|
||
|
During initialization, LinkUp checks if the configuration file exists. If it doesn't, the user is prompted to register a username and avatar. Once registered, the user can begin creating or joining chat rooms.
|
||
|
|
||
|
```javascript
|
||
|
async function initialize() {
|
||
|
if (!fs.existsSync("./config.json")) {
|
||
|
showRegistrationForm();
|
||
|
} else {
|
||
|
loadConfigFromFile();
|
||
|
await connectToAllRooms();
|
||
|
}
|
||
|
|
||
|
setupEventListeners();
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
## Bot
|
||
|
|
||
|
Integration
|
||
|
|
||
|
LinkUp features a bot system that runs as a separate process within the P2P network. This bot can automatically join chat rooms, respond to commands, and interact with users.
|
||
|
|
||
|
### Bot Architecture
|
||
|
|
||
|
The bot leverages the **Client** class to manage its connection to the Hyperswarm network. It listens for messages, executes commands, and can even send automated responses based on predefined triggers.
|
||
|
|
||
|
```javascript
|
||
|
const bot = new Client(botName);
|
||
|
|
||
|
bot.on('onMessage', (peer, message) => {
|
||
|
if (message.startsWith('!')) {
|
||
|
executeBotCommand(message, peer);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
bot.joinChatRoom(process.env.LINKUP_ROOM_ID);
|
||
|
```
|
||
|
|
||
|
### Supported Message Types
|
||
|
|
||
|
The bot supports various message types, including:
|
||
|
|
||
|
- **TextMessage**: Standard text messages.
|
||
|
- **FileMessage**: Messages containing file attachments.
|
||
|
- **AudioMessage**: Messages containing recorded audio clips.
|
||
|
|
||
|
Each message type is processed through its corresponding handler, enabling the bot to react dynamically to different content types.
|
||
|
|
||
|
|
||
|
|
||
|
## Challenges and Considerations
|
||
|
|
||
|
Building a decentralized chat application like LinkUp comes with several challenges, including:
|
||
|
|
||
|
- **Peer Discovery**: Ensuring efficient and fast peer discovery using Hyperswarm, especially in dynamic or large networks.
|
||
|
- **Security**: Managing peer connections securely, including encrypting messages and ensuring file integrity.
|
||
|
- **Data Persistence**: Handling file versioning and collaboration without relying on centralized databases or servers.
|
||
|
- **Performance**: Optimizing the performance of decentralized file storage and message broadcasting in real-time applications.
|
||
|
|
||
|
Despite these challenges, LinkUp demonstrates the power and potential of decentralized communication using cutting-edge peer-to-peer technologies.
|
||
|
|
||
|
|
||
|
|
||
|
## Final Thoughts
|
||
|
|
||
|
LinkUp showcases the possibilities of decentralized peer-to-peer communication by using the Hyperswarm and Hyperdrive libraries for real-time messaging and file sharing. With its event-driven architecture, extensible command system, and decentralized storage, LinkUp provides a secure and efficient platform for users to communicate without relying on centralized servers.
|
||
|
|
||
|
Whether you're interested in privacy-focused messaging, decentralized networks, or real-time collaboration, LinkUp offers a robust and scalable solution for peer-to-peer communication.
|