ravenscott-blog/markdown/LinkUp P2P Decentralized Chat.md
2024-09-16 10:28:53 -04:00

11 KiB

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

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:

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:
    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.

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:

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.

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.

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:

{
  "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.

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.

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.