Inside of the Beaker browser, we’ve implemented a set of new Web APIs for connecting apps to the peer-to-peer network. This is part 1 of a series about how to build peer-to-peer Web apps.

I recently published a peer-to-peer Photos app using the Beaker browser. Today we’ll step through how the app was built, and how you can make other peer-to-peer Web apps like it.

Introduction

The Photos app takes advantage of Beaker’s DatArchive API, which has methods for reading and writing the user’s filesystem, and for publishing the files on the peer-to-peer network.

App requirements

  1. The user should be able to create albums and upload photos to their albums
  2. The user should be able to share individual albums with friends

Where will the photos be stored?

If you were to build this app on the traditional Web, you’d store the user’s photos on your own server, or alternatively on a static storage service like Amazon S3 or Google Cloud Storage.

But inside of Beaker, publishing files on the peer-to-peer network is as simple as using a builtin Web API. So instead of uploading the images to a remote server, we can host the photos directly from the user’s device!

Building the app

The file structure of the app looks like this:

/css
-- album.css // CSS for the album page
-- base.css // shared CSS
-- main.css // CSS for the main app
/js
-- album.js
-- index.js
album.html
index.html

The index.html is used as the interface for the main app, and album.html provides the interface for the album pages.

How album.html is used might surprise you. We’ll talk about how it works in Step 1 below.

Step 1: Allow users to create albums

Step 1 is fairly simple, but it requires us to understand how peer-to-peer Web apps differ from traditional Web apps.

If we were building this app on the traditional Web, we’d store each album somewhere on a remote server. But in our app, each album will be represented as a new peer-to-peer website that’s stored and hosted from the user’s device.

So when the user clicks the “New album” button, the app will create a new website that represents the album and its photos. This means that in order to share an album with a friend, all you need to do is share the album’s dat:// URL!

To get started, we’ll add a click listener to the “New album” button in index.html:

document.querySelector(‘.create-album’).addEventListener(‘click’, onCreateAlbum)

Then we’ll define onCreateAlbum, which will create a new Dat archive to house everything that composes the album:

Let’s break this snippet down:

  • On line 3, we first create a new Dat archive, which serves as a website specifically for the album.
  • On line 10, we keep track of the user’s albums by storing it in localStorage.
  • On line 13, we read album.html from the main application’s Dat archive, and write it to index.html in the album’s archive. This means the album.html from the main app’s archive will actually serve as the main page for each album we create.

If you view the source for album.html, you’ll see that there are <script> and <link> tags that reference the main app’s CSS and JS, so if our app’s code is ever updated, the album pages will receive the updates from the main app.

Step 2: Implement photo uploading

Each album page has an <input type="file">, so in js/albums.js we add a change listener on that input. When photos are selected, we read the data from each of the selected files. Then, we write the image data to the album archive.

Note: the archive object in the example below comes from a setup function that sets the archive variable using Beaker’s DatArchive constructor:

const archive = new DatArchive(window.location)

Let’s start by reading the image files and writing them to the album’s archive. We use a FileReader to get the data from each selected photo, then use Beaker’s DatArchive.writeFile method to write to the archive.

Step 3: Display the user’s albums in the main app page

Recall that in step 1, when we created an album, we added the album’s URL to the albums array, and then wrote a stringified representation of the array to localStorage.

To display the albums, we’ll read the value of the albums item in localStorage, then render a preview of each album URL in the array.

In our setup function in js/index.js, we’ll start by reading the albums data fromlocalStorage:

Then for each album, we’ll render a preview of it in the main app:

Notice on line 23 that we use the url attribute on the album. Each archive has its own URL, so we can embed images from the archive just like any other web page.

And that’s it! Now we have an app that displays album previews, creates shareable photo albums, and hosts photos locally on the user’s device!

The app’s main page

Try it out yourself in Beaker! The app’s URL is:

dat://f0abcd6b1c4fc524e2d48da043b3d8399b96d9374d6606fca51182ee230b6b59/ 

Or view the full source.

Resources for building a peer-to-peer app