Libp2p Cookbook
This cookbook provides practical, goal-oriented recipes for common tasks you might want to accomplish with dart-libp2p.
Recipe: Building a Simple P2P Chat
Section titled “Recipe: Building a Simple P2P Chat”This recipe demonstrates how to build a simple, command-line chat application where two peers can exchange messages directly.
1. The Chat Protocol
Section titled “1. The Chat Protocol”First, we define a simple protocol for our chat application. When a peer wants to send a message, it will open a stream to the other peer using the protocol ID /chat/1.0.0 and write the message to it, followed by a newline character.
2. The ChatClient Class
Section titled “2. The ChatClient Class”We’ll create a ChatClient class to encapsulate the logic for sending and receiving messages.
import 'dart:async';import 'dart:convert';import 'dart:io';
import 'package:dart_libp2p/dart_libp2p.dart';
class ChatClient { final Host host; static const String protocolId = '/chat/1.0.0';
ChatClient(this.host) { // Set a stream handler for our chat protocol host.setStreamHandler(protocolId, _handleIncomingMessage); }
// Handler for incoming chat messages void _handleIncomingMessage(P2PStream stream, PeerId remotePeer) { print('[${host.id.toBase58().substring(0, 6)}] Received chat stream from [${remotePeer.toBase58().substring(0, 6)}]'); final reader = utf8.decoder.bind(stream.stream); reader.listen( (message) { // Display the received message print('\n[${remotePeer.toBase58().substring(0, 6)} says]: $message'); stdout.write('> '); }, onDone: () => print('Chat stream with ${remotePeer.toBase58().substring(0, 6)} closed.'), onError: (e) => print('Error on chat stream: $e'), ); }
// Send a message to a peer Future<void> sendMessage(PeerId targetPeer, String message) async { try { final stream = await host.newStream(targetPeer, [protocolId]); await stream.write(utf8.encode(message + '\n')); // The stream will be closed by the receiver after they read the message. // For a more robust chat, you'd keep the stream open. await stream.close(); } catch (e) { print('Error sending message to ${targetPeer.toBase58()}: $e'); } }}3. The Main Application
Section titled “3. The Main Application”Now, let’s wire everything together. We’ll create two hosts, connect them, and then start a loop to read messages from the command line and send them.
Future<Host> createHost() async { // ... (use the createHost function from the Getting Started guide)}
void main() async { // Create two hosts final host1 = await createHost(); final host2 = await createHost();
print('Host 1: ${host1.id.toBase58()} listening on ${host1.addrs}'); print('Host 2: ${host2.id.toBase58()} listening on ${host2.addrs}');
// Create chat clients for each host final chat1 = ChatClient(host1); final chat2 = ChatClient(host2);
// Connect host1 to host2 await host1.connect(AddrInfo(host2.id, host2.addrs)); print('\n--- Chat session started! ---'); print('Type a message and press Enter to send.'); print('Messages from you will be sent from [${host1.id.toBase58().substring(0, 6)}].'); print('---------------------------\n');
// Start a loop to read from stdin and send messages stdin.transform(utf8.decoder).transform(LineSplitter()).listen((line) { chat1.sendMessage(host2.id, line); stdout.write('> '); });
stdout.write('> ');}Running the Example
Section titled “Running the Example”When you run this code, you’ll see the PeerIDs and listen addresses for both hosts. The application will then wait for you to type a message. Anything you type will be sent from Host 1 to Host 2, and Host 2 will print it to the console.
This simple example illustrates the power of libp2p for building peer-to-peer applications. You can easily extend this to handle multiple peers, message history, and more complex interactions.