docs pass

This commit is contained in:
dmc
2024-01-10 15:08:54 +01:00
parent dbdeafec45
commit 9785189c9f
4 changed files with 174 additions and 150 deletions

View File

@@ -45,4 +45,5 @@ Pear loads applications from peers, so this command should launch [Keet](https:/
## Next
* [Making a Pear App](./making-a-pear-app.md)
* [Starting a Pear Desktop Project](./starting-a-pear-desktop-project.md)
* [Starting a Pear Terminal Project](./starting-a-pear-terminal-project.md)

View File

@@ -1,22 +1,136 @@
# Making a Pear Desktop Application
## Step 1. Install modules
This guide demonstrates how to build a straightforward peer-to-peer chat application.
This app uses these modules: `hyperswarm`, `hypercore-crypto`, and `b4a`.
The following steps walkthrough the feature implementations of chat room creation, connecting between users and sending messages.
## Step 1. HTML Structure and CSS Styles
This guide follows on from [Starting a Pear Desktop Project](./starting-a-pear-desktop-project.md).
We should have a project folder with the following files
- `package.json`
- `index.html`
- `app.js`
- `test/index.test.js`
Since this is a small chat application, we'll keep styles and HTML in one file.
``` html
<!DOCTYPE html>
<html>
<head>
<style>
body {
display: flex;
height: 100vh;
background-color: #3592C3;
color: white;
justify-content: center;
margin: 0;
padding: 0;
}
.hidden {
display: none !important;
}
#setup {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#loading {
align-self: center;
}
#chat {
display: flex;
flex-direction: column;
width: 100vw;
}
#header {
display: flex;
justify-content: space-between;
}
#messages {
flex: 1;
font-family: 'Courier New', Courier, monospace;
overflow-y: scroll;
}
#message-form {
display: flex;
}
#message {
flex: 1;
}
</style>
<script type='module' src='./app.js'></script>
</head>
<body>
<div id="setup">
<div>
<button id="create-chat-room">Create chat room</button>
</div>
<div>
- or -
</div>
<div>
<button id="join-chat-room">Join chat room</button>
<input id="join-chat-room-topic" type="text" placeholder="Topic for chat room" />
</div>
</div>
<div id="loading" class="hidden">Loading ...</div>
<div id="chat" class="hidden">
<div id="header">
<div>
Topic: <span id="chat-room-topic"></span>
</div>
<div>
Peers: <span id="peers-count">0</span>
</div>
</div>
<div id="messages"></div>
<form id="message-form">
<input id="message" type="text" />
<input type="submit" value="Send" />
</form>
</div>
</body>
</html>
```
After running with `pear dev` it should look like this:
![Layout of the app](../assets/chat-app-3.png)
## Step 2. Module dependencies
Our app is going to use these modules:
- [hyperswarm](https://www.npmjs.com/package/hyperswarm). One of the main building blocks. Find peers that share a "topic".
- [hypercore-crypto](https://www.npmjs.com/package/hypercore-crypto). A set of crypto functions.
- [b4a](https://www.npmjs.com/package/b4a). A set of functions for bridging the gap between the Node.js `Buffer` class and the `Uint8Array` class.
The dependencies can be installed with the following command:
```
$ npm i hyperswarm hypercore-crypto b4a
```
**Note**: If the modules are installed while the app is running an error is thrown similar to `Cannot find package 'hyperswarm' imported from /app.js`. When installing modules, close down the app, before they can be installed.
**Note**: If the modules are installed while the app is running, an error is thrown similar to `Cannot find package 'hyperswarm' imported from /app.js`. When installing modules, close down the app before attempting dependency installation.
- [hyperswarm](https://www.npmjs.com/package/hyperswarm). One of the main building blocks. Find peers that share a "topic".
- [hypercore-crypto](https://www.npmjs.com/package/hypercore-crypto). A set of crypto function used in Pear.
- [b4a](https://www.npmjs.com/package/b4a). A set of functions for bridging the gap between the Node.js `Buffer` class and the `Uint8Array` class.
## Step 3. Implement the program with JavaScript
## Step 2. Write the javascript code, using `hyperswarm`
Open `app.js` in a code editor and replace with this:
Open `app.js` in a code editor and replace the contents with the following:
``` js
import { teardown } from 'pear'
@@ -31,7 +145,8 @@ const swarm = new Hyperswarm()
teardown(() => swarm.destroy())
// When there's a new connection, listen for new messages, and add them to the UI
swarm.on('connection', peer => {
swarm.on('connection', (peer) => {
// name incoming peers after first 6 chars of its public key as hex
const name = b4a.toString(peer.remotePublicKey, 'hex').substr(0, 6)
peer.on('data', message => onMessageAdded(name, message))
})
@@ -51,13 +166,13 @@ async function createChatRoom() {
joinSwarm(topicBuffer)
}
async function joinChatRoom() {
async function joinChatRoom () {
const topicStr = document.querySelector('#join-chat-room-topic').value
const topicBuffer = b4a.from(topicStr, 'hex')
joinSwarm(topicBuffer)
}
async function joinSwarm(topicBuffer) {
async function joinSwarm (topicBuffer) {
document.querySelector('#setup').classList.add('hidden')
document.querySelector('#loading').classList.remove('hidden')
@@ -71,7 +186,7 @@ async function joinSwarm(topicBuffer) {
document.querySelector('#chat').classList.remove('hidden')
}
function sendMessage(e) {
function sendMessage (e) {
const message = document.querySelector('#message').value
document.querySelector('#message').value = ''
e.preventDefault()
@@ -80,59 +195,58 @@ function sendMessage(e) {
// Send the message to all peers (that you are connected to)
const peers = [...swarm.connections]
peers.forEach(peer => peer.write(message))
for (const peer of peers) peer.write(message)
}
function onMessageAdded(from, message) {
// appends element to #messages element with content set to sender and message
function onMessageAdded (from, message) {
const $div = document.createElement('div')
$div.textContent = `<${from}> ${message}`
document.querySelector('#messages').appendChild($div)
}
```
## Step 4. Run the app
> Note that code in `app.js` imports from `pear` but no `pear` dependency has been installed. This is the [Pear API](../reference/api.md)
Now it's time to write the app.
As there will be two apps running, open two terminals, and run this in both of them:
## Step 5 Open two application instances
As there will be two apps running, open two terminals and in each of them run the following:
```
$ pear dev
```
In the first app, click on `Create chat room`. When it has started the topic is at the top. This is a 32 byte public key that counts as the shared topic.
In the first app, click on `Create chat room`. Once the app has started the topic can be found near the top.
In the second app, paste in the topic that was shown in the first app, and then click on `Join chat room`.
Paste the topic from the first app into the input of the second app and then click on `Join chat room`.
<p align="center">
<img src="./assets/chat-app-4a.png" alt="The first app, with the topic"> <img src="../assets/chat-app-4b.png" alt="Second app, using topic from the first">
</p>
After that the two apps are able to send messages between them
View from the first app
Once connected messages can be sent between the applications.
<p align="center">
<img src="./assets/chat-app-5a.png" alt="View from the first app"> <img src="../assets/chat-app-5b.png" alt="View from the second app">
</p>
## Understand the code
### Discussion
Looking through the code, a great part of it has to do with handling the layout. It's outside of the scope of this tutorial to delve into that, but shouldn't look unfamiliar to most. It's possible to use larger frameworks like React, but that won't be covered here.
In a traditional client-server setup the server is hosted at an IP address (or hostname) and a port, e.g. `http://localhost:3000`. This is what clients use to connect to the server.
There are two main differences between a more common client-server chat app vs this peer-to-peer chat app
The code in `app.js` contains the line `swarm.join(topicBuffer, { client: true, server: true })`. Here `topicBuffer` is a 32 byte string. The creator of a chat room will generate a random byte string which acts as a room invinitation. Any peers with this invite (the topic) can use it to message to all other peers with the invite. Note also that both applications behave the same way, neither is only a client and neither is only a server.
### 1. Discovery
Applications join and leave topics so if the peer who created the topic/invite goes offline or even leaves the topic this has no effect on functionality.
In a traditional client-server setup the server is hosted on an ip (or hostname) and a port, e.g. `http://localhost:3000`. This is what clients use to connect to the server.
Two application instances are running on the same machine, connecting over a Distributed Hash Table (DHT) via `hyperswarm`.
In the code it says `swarm.join(topicBuffer, { client: true, server: true })`. Here `topicBuffer` is a 32 byte string. The creator of a chat room will generate a random byte string, which they will share with others, who can then join.
The code could be copied to another machine and `pear dev` could be ran on two machines instead of two terminals. However [Sharing a Pear Application](./sharing-a-pear-app.md) covers sharing the application itself over the same DHT. So then instead of copying, `pear` can be used to generate a topic for an app (the application key) and then that app on a peer machine by passing that key to the `pear` installation on that machine.
### 2. No servers
When the chat app was started there wasn't one of them that acting as a server, and another as a client. Instead they join/leave topics. This is an important point, because it means that even if the peer that created a chat room leaves, then it doesn't stop working.
> No frameworks were used to build this application but any frontend framework can be used with Pear.
## Next
Everything is starting to look good, and now that there's a running app, it's time to learn how we [share it with others](./sharing-a-pear-app.md).
* [Starting a Pear Terminal Project](./starting-a-pear-terminal-project.md)
* [Sharing a Pear Application](./sharing-a-pear-app.md)

View File

@@ -46,7 +46,7 @@ $ pear launch pear:nykmkrpwgadcd8m9x5khhh43j9izj123eguzqg3ygta7yn1s379o
This will download and open the app.
Note: Anyone running the app also help to seed it. So if the app had a lot of users, the original seeder could close down the process.
> Anyone running the app also help to seed it. So if an app has a lot of users the original seeder could close down the process with no consequences to application uptime/functionality.
## Next

View File

@@ -1,12 +1,10 @@
# Starting a Pear Project
# Starting a Pear Desktop Project
This tutorial will show how to create a basic chat app with Pear, and through that teach how to use some of the main building blocks.
In preparation for [Making a Pear Application](./making-a-pear-app.md) the following steps outline how to generate, configure, and develop a Pear Desktop Project.
In this first part of the app, users will be able to create chat rooms, connect to each other, and send messages.
## Step 1. Initialization
## Step 1. Init
First create a new project using `pear init`.
To create a new Pear project use `pear init`.
```
$ mkdir chat
@@ -21,7 +19,7 @@ This will create a base structure for the project.
- `app.js`. The main code.
- `test/index.test.js`. Skeleton for writing tests.
## Step 2. Test that everything works
## Step 2. Check that everything works
Before writing any code, make sure that everything works the way it's supposed to by using `pear dev`.
@@ -29,23 +27,32 @@ Before writing any code, make sure that everything works the way it's supposed t
$ pear dev
```
This will open the app. Because it's opened in development mode, developer tools are also opened.
This will open the app in development mode, by default developer tools are also opened.
![Running pear dev](../assets/chat-app-1.png)
## Step 3. Automatic reload
Pear apps have automatic reload included. This means that there is no need to stop and start the app again to see changes.
By default Pear watches project files and automatically reloads the page when files change.
While keeping the app open with `pear dev`, open `index.html` in a code editor. Change `<h1>chat</h1>` to `<h1>Hello world</h1>` and go to the app again. It should now look like this:
This means that there is no need to stop and start the app again to see changes.
While keeping the app open with `pear dev`, open `index.html` in a code editor.
Try changing `<h1>chat</h1>` to `<h1>Hello world</h1>` and look observe the app update.
It should now look like this:
![Automatic reload](../assets/chat-app-2.png)
## Step 4. Change Graphical User Interface (GUI) configuration
> Live reloading with hot-module reloading can be achieved with a combination of `pear.watch` configuration, [`pear.updates`](../reference/api.md#pearupdateslistener-async-functionfunction) API or the [pear-hotmods](https://github.com/holepunchto/pear-hotmods) convenience module.
It's possible to change various settings with Pear. This is done with the `pear` property in `package.json`
## Step 4. Configuration
Application configuration all happens via the `pear` property in `package.json`
For now, open `package.json` and update it like so:
For now, open `package.json` and update it :
```
{
...
@@ -60,110 +67,12 @@ For now, open `package.json` and update it :
}
```
When running the app now, it will be light blue, and have a different size.
If the app is open, close it and then run `pear dev` to see the configuration change.
See all the possibly options in the [Configuration Documentation](../reference/configuration.md).
## Step 5. Create a basic User Interface (UI)
To add some more interesting UI, let's have an example of a chat app, where users are able to create or join chat rooms and write messages to each other.
``` html
<!DOCTYPE html>
<html>
<head>
<style>
body {
display: flex;
height: 100vh;
background-color: #3592C3;
color: white;
justify-content: center;
margin: 0;
padding: 0;
}
.hidden {
display: none !important;
}
#setup {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#loading {
align-self: center;
}
#chat {
display: flex;
flex-direction: column;
width: 100vw;
}
#header {
display: flex;
justify-content: space-between;
}
#messages {
flex: 1;
font-family: 'Courier New', Courier, monospace;
overflow-y: scroll;
}
#message-form {
display: flex;
}
#message {
flex: 1;
}
</style>
<script type='module' src='./app.js'></script>
</head>
<body>
<div id="setup">
<div>
<button id="create-chat-room">Create chat room</button>
</div>
<div>
- or -
</div>
<div>
<button id="join-chat-room">Join chat room</button>
<input id="join-chat-room-topic" type="text" placeholder="Topic for chat room" />
</div>
</div>
<div id="loading" class="hidden">Loading ...</div>
<div id="chat" class="hidden">
<div id="header">
<div>
Topic: <span id="chat-room-topic"></span>
</div>
<div>
Peers: <span id="peers-count">0</span>
</div>
</div>
<div id="messages"></div>
<form id="message-form">
<input id="message" type="text" />
<input type="submit" value="Send" />
</form>
</div>
</body>
</html>
```
After running with `pear dev` it should look like this:
![Layout of the app](../assets/chat-app-3.png)
The initial background color will be light blue and the window will start with a different initial size.
See the [Configuration Documentation](../reference/configuration.md) for all configuration possibilities.
## Next
Now that there's some basic UI for a chat app, let's take a look at [making a Pear App](./making-a-pear-app.md).
* [Making a Pear Application](./making-a-pear-app.md).